In the code below I have managed to partially validate the data entered into the self.e2 entry widget, unfortunately if the entry widget is empty and the Submit button is pressed then a ValueError is generated" ValueError: invalid literal for int() with base 10: '' "
I would like to have the program recognise that the e2 entry widget is empty, have the ValueError trapped and return focus back to the entry widget.
I have attempted to do this using the is_valid_int and invalid_int methods but this is not working.
from tkinter import *
from tkinter import ttk
from tkinter.scrolledtext import *
class DailyOrderGUI:
def __init__(self, parent):
#Data entring frame
self.frame = Frame(parent, bg = "grey")
self.frame.grid(row=0)
self.label1 = Label(self.frame, text = "Mrs CackleBerry's Egg Ordering System", wraplength = 200, bg="grey", font=("Comic Sans MS", "14", "bold"))
self.label1.grid(row = 0, columnspan = 3, padx = 5, pady = 5)
self.superegg_img = PhotoImage(file = "images/superegg.gif")
self.label5 = Label(self.frame, bg="grey", image = self.superegg_img)
self.label5.grid(row = 0, column= 3, padx = 5, pady = 5)
self.v = StringVar()
self.v.set("Monday")
self.label2 = Label(self.frame, text = "Which day are you ordering for?", bg="grey", font=("Arial", "12", "bold"))
self.label2.grid(row = 1, columnspan = 4, sticky = W)
self.rb1 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Monday", text = "Monday")
self.rb1.grid(row = 2, column = 0, sticky = W)
self.rb2 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Tuesday", text = "Tuesday")
self.rb2.grid(row = 2, column = 1, sticky = W)
self.rb3 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Wednesday", text = "Wednesday")
self.rb3.grid(row = 2, column = 2, sticky = W)
self.rb4 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Thursday", text = "Thursday")
self.rb4.grid(row = 2, column = 3, sticky = W)
self.rb5 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Friday", text = "Friday")
self.rb5.grid(row = 3, column = 0, sticky = W)
self.rb6 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Saturday", text = "Saturday")
self.rb6.grid(row = 3, column = 1, sticky = W)
self.rb7 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Sunday", text = "Sunday")
self.rb7.grid(row = 3, column = 2, sticky = W)
self.label3 = Label(self.frame, text = "Customer's Name:?(Press \"Orders Complete\" to finish)", bg="grey", font=("Arial", "12", "bold"))
self.label3.grid(row = 4, columnspan = 4,padx = 5, sticky = W)
self.e1 = Entry(self.frame, width = 30)
self.e1.grid(row = 5, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e1.focus()
self.label4 = Label(self.frame, text = "How many eggs being ordered:?", bg="grey", font=("Arial", "12", "bold"))
self.label4.grid(row = 6, columnspan = 4,padx = 5,sticky = W)
integer = self.create_integer_widget()
self.btn1 = Button(self.frame, text = "Submit")
self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W)
self.btn1.bind("<Button-1>", self.get_orders)
self.btn2 = Button(self.frame, text = "Orders Complete", command = self.show_summary_result)
self.btn2.grid(row = 8, column = 3, padx = 5, pady = 3, sticky = E+W)
#Summary Frame
self.summ_frame = Frame(parent, bg = "grey")
self.summ_frame.grid(row=0)
self.summ_label1 = Label(self.summ_frame, text = "Mrs CackleBerry's Egg Ordering System", bg="grey", font=("Comic Sans MS", "14", "bold"))
self.summ_label1.grid(row = 0, columnspan = 4, padx = 5, pady = 5)
self.scrolled_display = ScrolledText(self.summ_frame, width = 50, height = 10, bg="thistle", font=("Times New Roman", "12"))
self.scrolled_display.grid(row = 1, columnspan = 2, padx = 5, pady = 20, sticky = W)
self.data_entry_btn = Button(self.summ_frame, text = "Back to Data Entry", command = self.show_data_entry_frame)
self.data_entry_btn.grid(row = 2, column = 0, sticky = SE, padx = 5, pady = 20)
self.egg_orders=[]
self.show_data_entry_frame()
def create_integer_widget(self):
self.e2 = ttk.Entry(self.frame, width = 10, validate='key')
self.e2['validatecommand'] = (self.frame.register(self.is_valid_int), '%P')
self.e2['invalidcommand'] = (self.frame.register(self.invalid_int), '%W')
self.e2.grid(row = 7, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e2.bind("<Return>", self.get_orders)
return self.e2
def is_valid_int(self, txt):
# txt - value in %P
if not txt: # do not accept empty string
return False
try:
int(txt)
return True # accept integer
except ValueError: # not an integer
return False
def invalid_int(self, widgetName):
# called automatically when the
# validation command returns 'False'
# get entry widget
widget = self.frame.nametowidget(widgetName)
# clear entry
widget.delete(0, END)
# return focus to integer entry
widget.focus_set()
widget.bell()
def show_data_entry_frame(self):
self.summ_frame.grid_remove()
self.frame.grid()
root.update_idletasks()
def show_summary_result(self):
self.frame.grid_remove()
self.summ_frame.grid()
root.update_idletasks()
self.scrolled_display.delete('1.0', END)
if len(self.egg_orders) == 0:
self.scrolled_display.insert(END, "No Orders")
else:
total = 0
self.scrolled_display.insert(END, "Orders for " + self.v.get() + "\n")
for i in range(len(self.egg_orders)):
total += self.egg_orders[i].num_eggs
self.scrolled_display.insert(END, str(self.egg_orders[i]) + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Summary for " + self.v.get() + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Total eggs: " + str(total) + "\n")
self.scrolled_display.insert(END, "Dozens required: " + str(self.get_dozens(total)) + "\n")
average = 0
if len(self.egg_orders) > 0:
average = total / len(self.egg_orders)
self.scrolled_display.insert(END, "Average number of eggs per customer: {0:.1f}".format(average) + "\n")
def get_orders(self, event):
"""
Collects order information - name, number of eggs in a loop
"""
self.name = self.e1.get()
self.no_eggs = self.e2.get()
self.e1.delete(0, END)
self.e2.delete(0, END)
self.e1.focus()
self.egg_orders.append(EggOrder(self.name, self.no_eggs))
def get_dozens (self, total):
"""
returns whole number of dozens required to meet required number of eggs
"""
num_dozens = total//12
if total%12 != 0:
num_dozens += 1
return num_dozens
class EggOrder:
price_per_doz = 6.5
def __init__(self, name, num_eggs):
self.name = name
self.num_eggs = int(num_eggs)
def calc_price(self):
self.price = EggOrder.price_per_doz/12 * self.num_eggs
return self.price
def __str__(self):
return("{} ordered {} eggs. The price is ${:.2f}".format(self.name, self.num_eggs , self.calc_price()))
#main routine
if __name__== "__main__":
root = Tk()
root.title("Mrs Cackleberry's Egg Ordering Program")
frames = DailyOrderGUI(root)
root.mainloop()
Let's trace through what happens when you click "Submit".
First:
self.btn1 = Button(self.frame, text = "Submit")
self.btn1.grid(row = 8, padx = 5, pady = 3, sticky = E+W)
self.btn1.bind("<Button-1>", self.get_orders)
So, it calls self.get_orders. And the last line in that function is:
self.no_eggs = self.e2.get()
# ...
self.egg_orders.append(EggOrder(self.name, self.no_eggs))
And inside the EggOrder.__init__ function you've got this:
self.num_eggs = int(num_eggs)
That's presumably where the error happens.
(Note that all of that work would have been unnecessary if you'd posted the traceback instead of just the error string.)
So, when self.e2.get() returns an empty string, you end up calling int(''), and that raises a ValueError.
Unless you want to try to check for that possibility in advance (which is rarely a good idea), you will need a try:/except ValueError: somewhere. The question is, where? Well, that depends on what you want to do.
If you want to create an empty EggOrder, you'd do it inside EggOrder.__init__:
try:
self.num_eggs = int(num_eggs)
except ValueError:
self.num_eggs = 0
On the other hand, if you want to not create an EggOrder at all, you'd do it inside self.get_orders:
try:
order = EggOrder(self.name, self.no_eggs)
except ValueError:
# pop up an error message, log something, call self.invalid_int, whatever
else:
self.egg_orders.append(order)
Of course you probably want to do this before all the destructive stuff (self.e1.delete(0, END), etc.).
Also, if you wanted to call invalid_int as-is, you'd need to pass it the name of the self.e2 widget. Since you didn't give it one, it'll be something dynamic and unpredictable like .1234567890, which you'll have to ask the widget for, just so you can look the widget back up by that name. It would be simpler to factor out the core functionality, something like this:
def invalid_int(self, widgetName):
widget = self.frame.nametowidget(widgetName)
self.handle_invalid_int(widget)
def handle_invalid_int(self, widget):
widget.delete(0, END)
# etc.
Then you can just call handle_invalid_int(self.e2).
Meanwhile, you've tried adding a validation function to check for a valid int input.
is_valid_int should work fine. However, the if not txt part is completely unnecessary—int(txt) will already handle an empty string the same way it handles a non-numeric string.
And the way you've hooked it up should work too.
However, a validation function runs on each edit to the Entry widget, not when you click some other random widget elsewhere. For example, if you try typing letters into the Entry, it should erase them as soon as you can type them. (Note that if you type 123a456 you'll end up with 456, not 123456, which may or may not be what you want…)
So, you've done that right, but it's not what you wanted to do.
Related
I really need help, my brain is melting because of this problem. I've studied python for 2 months maybe and I'm not very expert in programming. I've got an issue... I'm using tkinter on this program; in this small GUI I'd like to always keep updated the global variable "temp", and its value should change everytime I click on the button. I know that mainloop() is a blocking method, so it is possible to do something like this?
import tkinter as tk
class App:
def __init__(self):
super().__init__()
self.screen = tk.Tk()
self.screen.geometry("400x400")
self.screen.title("Modifica temperatura ambiente")
self.screen.grid_columnconfigure(0, weight = 1)
self.label = tk.Label(self.screen, text="ENTER TEMPERATUR VALUE", fg = "black", font = ("Calibri", 10) )
self.label.grid(row = 0, column = 0, sticky = "N", pady = 10)
self.input_ = tk.Entry(self.screen)
self.input_.grid(row = 1, column = 0, sticky = "WE", pady = 5, padx = 20)
self.button = tk.Button(self.screen, text = "INVIA", command = self.getvalue)
self.button.grid(row = 2, column = 0, sticky = "WE", pady = 5, padx = 10)
def getvalue(self):
self.temp = self.input_.get()
temperatura_label = tk.Label(self.screen, text = "Last input value is " + self.temp + " degrees", fg = "red")
temperatura_label.grid(row = 3, column = 0, sticky = "S")
return self.temp
app = App()
temp = app.getvalue()
print(temp)
app.screen.mainloop()
Thank for the help!
If you want to print it in the terminal, modify your getvalue function.
Code:
import tkinter as tk
screen = tk.Tk()
screen.geometry("400x400")
screen.title("Modifica temperatura ambiente")
screen.grid_columnconfigure(0, weight = 1)
class App:
def __init__(self, master):
super().__init__()
self.master = master
self.label = tk.Label(master, text="ENTER TEMPERATUR VALUE", fg = "black", font = ("Calibri", 10) )
self.label.grid(row = 0, column = 0, sticky = "N", pady = 10)
self.input_ = tk.Entry(master)
self.input_.grid(row = 1, column = 0, sticky = "WE", pady = 5, padx = 20)
def getvalue(self):
self.temp = self.input_.get()
temperatura_label = tk.Label(self.master, text = "Last input value is " + self.temp + " degrees", fg = "red")
temperatura_label.grid(row = 3, column = 0, sticky = "S")
if self.temp == None:
print()
else:
return self.temp
app = App(screen)
def main_loop():
global app
temp = app.getvalue()
print(temp)
button = tk.Button(screen, text = "INVIA", command = main_loop)
button.grid(row = 2, column = 0, sticky = "WE", pady = 5, padx = 10)
screen.mainloop()
I want to make a button in my widget that when I press it, it proceeds to the next lines of code, and closes the existing widget of where the button is.
from tkinter import *
root = Tk()
Label(root, text = "Childs First name").grid(row = 0, sticky = W)
Label(root, text = "Childs Surname").grid(row = 1, sticky = W)
Label(root, text = "Childs Year of Birth").grid(row = 2, sticky = W)
Label(root, text = "Childs Month of Birth").grid(row = 3, sticky = W)
Label(root, text = "Childs Day of Birth").grid(row = 4, sticky = W)
Fname = Entry(root)
Sname = Entry(root)
x = Entry(root)
y = Entry(root)
z = Entry(root)
Fname.grid(row = 0, column = 1)
Sname.grid(row = 1, column = 1)
x.grid(row = 3, column = 1)
y.grid(row = 2, column = 1)
z.grid(row = 4, column = 1)
button1 = Button(root, text = "Quit", command = root.quit, bg = "Grey", fg = "White", width = 12).grid(row = 5, column = 0, sticky = W)
def save():
Fname_value = Fname.get()
Sname_value = Sname.get()
x_value = x.get()
y_value = y.get()
z_value = z.get()
save()
mainloop()
Sorry for this late answer. To make a 'continue' button:
continue_button = tk.Button(frame,text='continue',command=func)
continue_button.config(width=width_continue_button)
# set the coordinates as you want. here 2,6 for the example
continue_button.grid(row=2,column=6,padx=width_continue_grid)
then you have to write the function 'func' to fulfill your needs.
hope this helps
This question already has answers here:
Tkinter: AttributeError: NoneType object has no attribute <attribute name>
(4 answers)
Closed 7 years ago.
So I'm trying to write some code that takes two user inputted values, compares them, and then tells the user if he/she input the correct values. (USL should be greater than LSL, pretty simple criteria) Here you can see how i get the entry from the user
# get USL and LSL
Label(self, text = "USL").grid(row = 5, column = 0, sticky = W, padx=5, pady=5)
self.e6 = Entry(self).grid(row = 5, column = 1)
Label(self, text = "LSL").grid(row = 6, column = 0, sticky = W, padx=5, pady=5)
self.e7 = Entry(self).grid(row = 6, column = 1)
This next bit of code is where I check the code
# button to check USL is higher than LSL
self.button = Button(self)
self.button["text"] = "Check USL and LSL"
self.button["command"] = self.check_limits
self.button.grid(row = 6, column = 2, sticky = W, padx=5, pady=5)
and finally here is where i define the check_limits function
def check_limits(self):
e6 = int(self.e6)
e7 = int(self.e7)
if e6 > e7:
message = "Limits are good"
else:
message = "USL can't be less than LSL, please re-enter USL and LSL"
self.text.delete(0.0, END)
self.text.insert(0.0, message)
Currently I have the variables e6 and e7 forced as integers, but when i do this I get an error saying that int() arguments must be a string or a number, not "NoneType". Why would they be defined as null and not integers in this case?
Alternatively, if I don't force them to be integers then I always get "USL can't be less than...", regardless of whether e6 is greater or less than e7. Why is it doing this and how do I fix it?
Here's my entire code if any else of it is needed for the context of this question
from Tkinter import *
class Application(Frame):
""" A SPC program that takes user input and saves the file """
def __init__(self,master):
""" initializes the frame """
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""create widgets for user inputted data"""
# get name
Label(self, text = "First Name").grid(row = 0, column = 0, sticky = W, padx=5, pady=5)
self.e1 = Entry(self).grid(row = 0, column = 1)
Label(self, text = "Last Name").grid(row = 1, column = 0, sticky = W, padx=5, pady=5)
self.e2 = Entry(self).grid(row = 1, column = 1)
# get work order
Label(self, text = "Work Order Number").grid(row = 2, column = 0, sticky = W, padx=5, pady=5)
self.e3 = Entry(self).grid(row = 2, column = 1)
# get todays date
Label(self, text = "Todays Date").grid(row = 3, column = 0, sticky = W, padx=5, pady=5)
self.e4 = Entry(self).grid(row = 3, column = 1)
# get bubble number
Label(self, text = "Bubble Number").grid(row = 4, column = 0, sticky = W, padx=5, pady=5)
self.e5 = Entry(self).grid(row = 4, column = 1)
# get USL and LSL
Label(self, text = "USL").grid(row = 5, column = 0, sticky = W, padx=5, pady=5)
self.e6 = Entry(self).grid(row = 5, column = 1)
Label(self, text = "LSL").grid(row = 6, column = 0, sticky = W, padx=5, pady=5)
self.e7 = Entry(self).grid(row = 6, column = 1)
# button to check USL is higher than LSL
self.button = Button(self)
self.button["text"] = "Check USL and LSL"
self.button["command"] = self.check_limits
self.button.grid(row = 6, column = 2, sticky = W, padx=5, pady=5)
# creates a spot to dictate whether USL and LSL are correct
self.text = Text(self, width = 35, height = 2, wrap = WORD)
self.text.grid(row = 6, column = 3, sticky = W)
def check_limits(self):
e6 = int(self.e6)
e7 = int(self.e7)
if e6 > e7:
message = "Limits are good"
else:
message = "USL can't be less than LSL, please re-enter USL and LSL"
self.text.delete(0.0, END)
self.text.insert(0.0, message)
root = Tk()
root.title("SPC Input Program")
root.geometry("700x500")
app = Application(root)
root.mainloop()
Your issue is this
self.e6 = Entry(self).grid(row = 5, column = 1)
When you want to use an assigned widget you can't pack, place or grid it. You need to change it to this
self.e6 = Entry(self)
self.e6.grid(row = 5, column = 1)
You are getting NoneType because of the assignment with the grid. Doing that is fine for static widgets like Labels and Buttons you don't plan on accessing. But when you want to get or assign a value to the widget, it needs to be the widget itself and not widget.grid()
So several other people have asked similar questions, but I don't think they necessarily apply to my situation. I'm writing a program that's eventually going to take user inputs, check to make sure they correct, and then save it all to a file. Currently, I'm passing all the user inputs to a text box in tkinter so that I can just save whatever's in that one text box. I'm using a for loop to go through the 7 user entry fields I have and then insert them into the text box.
def submit(self):
""" submits user data up to input data section of GUI and checks USL vs LSL"""
e6 = IntVar(self.e6)
e7 = IntVar(self.e7)
if e6 > e7:
message = "Limits are good"
else:
message = "USL can't be less than LSL, please re-enter USL and LSL"
self.checklimits.delete(0.0, END)
self.checklimits.insert(0.0, message)
x = 1
for x in range (1, 8):
xname = "self.e" + str(x)
entry = xname.get()
if entry:
self.checktext.insert(END, entry + "\n")
x = x+1
I'm wanting to take the x value in the for loop and eventually end up with something like "self.e#.get()" since that's how i've defined the user entries, see example below:
def create_widgets(self):
"""create widgets for user inputted data"""
# creates a text widget next to the entries that displays what the user has input
Label(self, text = "Do these values you entered seem correct?").grid(row = 0, column = 4, sticky = W, padx = 5, pady = 5)
self.checktext = Text(self, width =15, height = 42, wrap = WORD)
self.checktext.grid(row = 1, rowspan = 10, column = 4, sticky = W, padx =5, pady =5)
# get name
Label(self, text = "First Name:").grid(row = 0, column = 0, sticky = W, padx=5, pady=5)
self.e1 = Entry(self)
self.e1.grid(row = 0, column = 1)
Label(self, text = "Last Name:").grid(row = 1, column = 0, sticky = W, padx=5, pady=5)
self.e2 = Entry(self)
self.e2.grid(row = 1, column = 1)
Right now though, python isn't recognizing that entry as an entry and is saying back to me that "'str' object has no attribute 'get'"
So for one, why can't I "get" a string value, and two, how can I get python to recognize my previously defined entry? Here's my entire code for context
from Tkinter import *
class Application(Frame):
""" A SPC program that takes user input and saves the file """
def __init__(self,master):
""" initializes the frame """
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
"""create widgets for user inputted data"""
# creates a text widget next to the entries that displays what the user has input
Label(self, text = "Do these values you entered seem correct?").grid(row = 0, column = 4, sticky = W, padx = 5, pady = 5)
self.checktext = Text(self, width =15, height = 42, wrap = WORD)
self.checktext.grid(row = 1, rowspan = 10, column = 4, sticky = W, padx =5, pady =5)
# get name
Label(self, text = "First Name:").grid(row = 0, column = 0, sticky = W, padx=5, pady=5)
self.e1 = Entry(self)
self.e1.grid(row = 0, column = 1)
Label(self, text = "Last Name:").grid(row = 1, column = 0, sticky = W, padx=5, pady=5)
self.e2 = Entry(self)
self.e2.grid(row = 1, column = 1)
# get work order
Label(self, text = "Work Order Number:").grid(row = 2, column = 0, sticky = W, padx=5, pady=5)
self.e3 = Entry(self)
self.e3.grid(row = 2, column = 1)
# get todays date
Label(self, text = "Todays Date:").grid(row = 3, column = 0, sticky = W, padx=5, pady=5)
self.e4 = Entry(self)
self.e4.grid(row = 3, column = 1)
# get bubble number
Label(self, text = "Bubble Number:").grid(row = 4, column = 0, sticky = W, padx=5, pady=5)
self.e5 = Entry(self)
self.e5.grid(row = 4, column = 1)
# get USL and LSL
Label(self, text = "USL:").grid(row = 5, column = 0, sticky = W, padx=5, pady=5)
self.e6 = Entry(self)
self.e6.grid(row = 5, column = 1)
Label(self, text = "LSL:").grid(row = 6, column = 0, sticky = W, padx=5, pady=5)
self.e7 = Entry(self)
self.e7.grid(row = 6, column = 1)
"""# button to check USL is higher than LSL
self.button7 = Button(self)
self.button7["text"] = "Check Limits"
self.button7["command"] = self.check_limits
self.button7.grid(row = 6, column = 2, sticky = W, padx=5, pady=5)"""
# button to submit user entered values up to the input data values portion of the gui
self.button6 = Button(self)
self.button6["text"] = "Submit"
self.button6["command"] = self.submit
self.button6.grid(row = 5, column = 2, sticky = W, padx=5, pady=5)
# creates a spot to dictate whether USL and LSL are correct
self.checklimits = Text(self, width = 20, height = 2, wrap = WORD)
self.checklimits.grid(row = 6, column = 3, sticky = W, padx = 5)
""" #adds a scroll bar to the data input text box
scrollbar = Scrollbar(self)
scrollbar.pack(side=RIGHT, fill=Y) """
# get User Input Data values
Label(self, text = "Enter Results:").grid(row = 7, column = 0, sticky = W, padx=5, pady=5)
self.e8 = Text(self, width = 15, height = 30)
self.e8.grid(row = 7, column = 1)
""" def check_limits(self):
checks to see if the USL is greater than the LSL
e6 = IntVar(self.e6)
e7 = IntVar(self.e7)
if e6 > e7:
message = "Limits are good"
else:
message = "USL can't be less than LSL, please re-enter USL and LSL"
self.checklimits.delete(0.0, END)
self.checklimits.insert(0.0, message)"""
def submit(self):
""" submits user data up to input data section of GUI and checks USL vs LSL"""
e6 = IntVar(self.e6)
e7 = IntVar(self.e7)
if e6 > e7:
message = "Limits are good"
else:
message = "USL can't be less than LSL, please re-enter USL and LSL"
self.checklimits.delete(0.0, END)
self.checklimits.insert(0.0, message)
x = 1
for x in range (1, 8):
xname = "self.e" + str(x)
entry = xname.get()
if entry:
self.checktext.insert(END, entry + "\n")
x = x+1
root = Tk()
root.title("SPC Input Program")
root.geometry("700x750")
app = Application(root)
root.mainloop()
It appears that you are assuming that e6 = IntVar(self.e6) is getting the value of an entry widget and converting it to an int. That's not what it's doing. It is creating a new variable named e6 that is initialized to zero, and has self.e6 as the "master".
If you want to get the values from an entry widget and convert it to an integer, use the get method on the entry widget.
e6 = int(self.e6.get())
e7 = int(self.e7.get())
The problem that is causing the "str object has no method get" is this code:
xname = "self.e" + str(x)
entry = xname.get()
This is a terrible way to code. As you can see, it won't work. You can make it work with tricks, but a good rule of thumb is to never try to dynamically create variables like this.
If you want to loop over the entry widgets, put them in a list or tuple. For example:
for widget in (self.e1, self.e2, self.e3, self.e4,
self.e5, self.e6, self.e7, self.e8):
entry = widget.get()
if entry:
self.checktext.insert(END, entry + "\n")
...
The following code is giving 'Daily Order Object' has no attribute 'register'. I have no idea why this would be - any help gladly accepted.
I am trying to validate the Entry widget and am trying to use what I thought was a universal method .register() to do register a function "is_valid_int()" that would check that the Entry widget contains an integer.
from tkinter import *
from tkinter.scrolledtext import *
class DailyOrderGUI:
def __init__(self, parent):
#Data entring frame
self.frame = Frame(parent, bg = "grey")
self.frame.grid(row=0)
self.label1 = Label(self.frame, text = "Mrs CackleBerry's Egg Ordering System", bg="grey", font=("Comic Sans MS", "14", "bold"))
self.label1.grid(row = 0, columnspan = 4, padx = 5, pady = 5)
self.v = StringVar()
self.v.set("Monday")
self.label2 = Label(self.frame, text = "Which day are you ordering for?", bg="grey", font=("Arial", "12", "bold"))
self.label2.grid(row = 1, columnspan = 4, sticky = W)
self.rb1 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Monday", text = "Monday")
self.rb1.grid(row = 2, column = 0, sticky = W)
self.rb2 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Tuesday", text = "Tuesday")
self.rb2.grid(row = 2, column = 1, sticky = W)
self.rb3 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Wednesday", text = "Wednesday")
self.rb3.grid(row = 2, column = 2, sticky = W)
self.rb4 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Thursday", text = "Thursday")
self.rb4.grid(row = 2, column = 3, sticky = W)
self.rb5 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Friday", text = "Friday")
self.rb5.grid(row = 3, column = 0, sticky = W)
self.rb6 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Saturday", text = "Saturday")
self.rb6.grid(row = 3, column = 1, sticky = W)
self.rb7 = Radiobutton(self.frame, variable = self.v, bg="grey", value = "Sunday", text = "Sunday")
self.rb7.grid(row = 3, column = 2, sticky = W)
self.label3 = Label(self.frame, text = "Customer's Name:?(Press \"Orders Complete\" to finish)", bg="grey", font=("Arial", "12", "bold"))
self.label3.grid(row = 4, columnspan = 4,padx = 5,sticky = W)
self.e1 = Entry(self.frame, width = 30)
self.e1.grid(row = 5, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e1.focus()
self.label4 = Label(self.frame, text = "How many eggs being ordered:?", bg="grey", font=("Arial", "12", "bold"))
self.label4.grid(row = 6, columnspan = 4,padx = 5,sticky = W)
vcmd = (self.register(self.is_valid_int),"%P")
self.e2 = Entry(self.frame, width = 10, validate='all', validatecommand=vcmd)
self.e2.grid(row = 7, columnspan = 4, sticky = W, padx = 5, pady=3)
self.e2.bind("<Return>", self.get_orders)
self.btn1 = Button(self.frame, text = "Submit")
self.btn1.grid(row = 8, padx = 5, sticky = E+W)
self.btn1.bind("<Button-1>", self.get_orders)
self.btn2 = Button(self.frame, text = "Orders Complete", command = self.show_summary_result)
self.btn2.grid(row = 8, column = 3, padx = 5, sticky = E+W)
#Summary Frame
self.summ_frame = Frame(parent, bg = "grey")
self.summ_frame.grid(row=0)
self.summ_label1 = Label(self.summ_frame, text = "Mrs CackleBerry's Egg Ordering System", bg="grey", font=("Comic Sans MS", "14", "bold"))
self.summ_label1.grid(row = 0, columnspan = 4, padx = 5, pady = 5)
self.scrolled_display = ScrolledText(self.summ_frame, width = 50, height = 10, bg="thistle", font=("Times New Roman", "12"))
self.scrolled_display.grid(row = 1, columnspan = 2, padx = 5, pady = 20, sticky = W)
self.data_entry_btn = Button(self.summ_frame, text = "Back to Data Entry", command = self.show_data_entry_frame)
self.data_entry_btn.grid(row = 2, column = 0, sticky = SE, padx = 5, pady = 20)
self.egg_orders=[]
self.show_data_entry_frame()
def is_valid_int(self, txt):
# txt - value in %P
if not txt: # accept empty string
return True
try:
int(txt)
return True # accept integer
except ValueError: # not an integer
return False
def invalid_int(self, widgetName):
# called automatically when the
# validation command returns 'False'
# get entry widget
widget = self.nametowidget(widgetName)
# clear entry
widget.delete(0, END)
# return focus to integer entry
widget.focus_set()
widget.bell()
def show_data_entry_frame(self):
self.summ_frame.grid_remove()
self.frame.grid()
root.update_idletasks()
def show_summary_result(self):
self.frame.grid_remove()
self.summ_frame.grid()
root.update_idletasks()
self.scrolled_display.delete('1.0', END)
if len(self.egg_orders) == 0:
self.scrolled_display.insert(END, "No Orders")
else:
total = 0
self.scrolled_display.insert(END, "Orders for " + self.v.get() + "\n")
for i in range(len(self.egg_orders)):
total += self.egg_orders[i].num_eggs
self.scrolled_display.insert(END, str(self.egg_orders[i]) + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Summary for " + self.v.get() + "\n")
self.scrolled_display.insert(END, "" + "\n")
self.scrolled_display.insert(END, "Total eggs: " + str(total) + "\n")
self.scrolled_display.insert(END, "Dozens required: " + str(self.get_dozens(total)) + "\n")
average = 0
if len(self.egg_orders) > 0:
average = total / len(self.egg_orders)
self.scrolled_display.insert(END, "Average number of eggs per customer: {0:.1f}".format(average) + "\n")
def get_orders(self, event):
"""
Collects order information - name, number of eggs in a loop
"""
self.name = self.e1.get()
self.no_eggs = self.e2.get()
self.e1.delete(0, END)
self.e2.delete(0, END)
self.e1.focus()
self.egg_orders.append(EggOrder(self.name, self.no_eggs))
def get_dozens (self, total):
"""
returns whole number of dozens required to meet required number of eggs
"""
num_dozens = total//12
if total%12 != 0:
num_dozens += 1
return num_dozens
class EggOrder:
price_per_doz = 6.5
def __init__(self, name, num_eggs):
self.name = name
self.num_eggs = int(num_eggs)
def calc_price(self):
self.price = EggOrder.price_per_doz/12 * self.num_eggs
return self.price
def __str__(self):
return("{} ordered {} eggs. The price is ${:.2f}".format(self.name, self.num_eggs , self.calc_price()))
#main routine
if __name__== "__main__":
root = Tk()
root.title("Mrs Cackleberry's Egg Ordering Program")
frames = DailyOrderGUI(root)
root.mainloop()
your class DailyOrderGUI: doesn't implement nor inherit method register.
Propobly you need inherit it form other widget