Related
This question already has answers here:
Why is my Button's command executed immediately when I create the Button, and not when I click it? [duplicate]
(5 answers)
Closed 5 years ago.
So I'm pretty new to coding and I'm trying to make a simple menu program with tkinter that would let the user click on certain food items and it will display his/her total.
When I run the program python says AttributeError: 'Menu' object has no attribute 'potato_skins'. When I take out "potato skins" it says I do not have the attribute of bread, and so on and so forth.
Can someone please help me, here is the code:
#Order Up!
#restaurant menu that lets the user pick foods, then show overall price
from tkinter import *
class Menu(Frame):
"""Menu that let's the user choose food and shows the total price."""
def __init__(self, master):
"""Initialize the frame"""
super(Menu, self).__init__(master)
self.grid()
self.menu_widgets()
def menu_widgets(self):
"""Create all the menu items."""
#Appetizer Label
Label(self,
text = "Choose your appetizers:"
).grid(row = 0, column = 0, sticky = W)
#Appetizer checkbuttons
self.motzerella_sticks = BooleanVar()
Checkbutton(self,
text = "Mozzerella sticks, $5",
variable = self.motzerella_sticks,
command = self.update_total()
).grid(row = 1, column = 1, sticky = W)
self.potato_skins = BooleanVar()
Checkbutton(self,
text = "potato skins, $7",
variable = self.potato_skins,
command = self.update_total()
).grid(row = 1, column = 1, sticky = W)
self.bread = BooleanVar()
Checkbutton(self,
text = "bread, $0",
variable = self.bread,
command = self.update_total()
).grid(row = 1, column = 2, sticky = W)
#Entree Label
Label(self,
text = "Pick your entree:"
).grid(row = 2, column = 0, sticky = W)
#Entree Checkbuttons
self.chicken = BooleanVar()
Checkbutton(self,
text = "chicken and brocolli, $10",
variable = self.chicken,
command = self.update_total()
).grid(row = 3, column = 0, sticky = W)
self.soup = BooleanVar()
Checkbutton(self,
text = "brocolli cheddar soup, $12",
variable = self.soup,
command = self.update_total()
).grid(row = 3, column = 1, sticky = W)
self.pasta = BooleanVar()
Checkbutton(self,
text = "alfredo pasta, $15",
variable = self.pasta,
command = self.update_total()
).grid(row = 3, column = 2, sticky = W)
#Dessert Label
Label(self,
text = "Choose your dessert:"
).grid(row = 4, column = 0, sticky = W)
#Dessert Checkbuttons
self.cake = BooleanVar()
Checkbutton(self,
text = "Chocolate cake, $15",
variable = self.cake,
command = self.update_total()
).grid(row = 5, column = 0, sticky = W)
self.brownie = BooleanVar()
Checkbutton(self,
text = "Brownies, $13",
variable = self.brownie,
command = self.update_total()
).grid(row = 5, column = 1, sticky = W)
#create a Text box to display total
self.total_txt = Text(self, width = 40, height = 5, wrap = WORD)
self.total_txt.grid(row = 6, column = 0, columnspan = 2, sticky = W)
def update_total(self):
"""Show the total"""
total = 0
if self.motzerella_sticks.get():
total += 5
if self.potato_skins.get():
total += 7
if self.bread.get():
total += 0
if self.chicken.get():
total += 10
if self.soup.get():
total += 12
if self.pasta.get():
total += 15
if self.cake.get():
total += 15
if self.brownie.get():
total += 13
self.total_txt.delete(0.0, END)
self.total_txt.insert(0.0, "Your total is: ", total)
#main
root = Tk()
root.title("Menu")
app = Menu(root)
root.mainloop()
The reason is that you execute your function instead of passing it as the command parameter.
command = self.update_total()
This means its executed when creating the CheckButton associated with self.motzerella_sticks. At this point self.potato_skins does not exist.
To fix it, pass the function, rather than executing it.
command = self.update_total
The problem in that I can't pickle the text in entry fields. I try to make it in the 'record' function.
Error: can't pickle _tkinter.tkapp objects
I want to save data in the file and then read it.
Interface:
#program to record and store your sports results
import shelve
from tkinter import *
class Application(Frame):
'''GUI application ере displays menu for the programm'''
def __init__(self, master):
'''Initialize Frame'''
super(Application, self).__init__(master)
self.grid()
self.create_widgets()
def create_widgets(self):
''' Create widgets to get story information and to display story. '''
self.fileDat = 'data'
# label date
Label(self,
text = "date:"
).grid(row = 0, column = 0, columnspan = 2, sticky = W)
# field date
self.date_ent = Entry(self)
self.date_ent.grid(row = 1, column = 1, sticky = W)
# label №
Label(self,
text = "№:"
).grid(row = 0, column = 3, columnspan = 2, sticky = W)
# field №
self.number_ent = Entry(self)
self.number_ent.grid(row = 1, column = 4, sticky = W)
# label km
Label(self,
text = "km:"
).grid(row = 2, column = 0, columnspan = 2, sticky = W)
# field km
self.km_ent = Entry(self)
self.km_ent.grid(row = 3, column = 1, sticky = W)
# label time
Label(self,
text = "time:"
).grid(row = 3, column = 0, columnspan = 2, sticky = W)
# field time
self.time_ent = Entry(self)
self.time_ent.grid(row = 4, column = 1, sticky = W)
# record button
Button(self,
text = "record training",
command = self.record
).grid(row = 5, column = 0, sticky = W)
# show training button
Button(self,
text = "show trining",
command = self.tngDisplay
).grid(row = 5, column = 3, sticky = W)
self.tngField = Text(self, width = 75, height = 10, wrap = WORD)
self.tngField.grid(row = 6, column = 0, columnspan = 4)
def listRecord( self):
date = self.date_ent.get()
km = self.km_ent.get()
time = self.time_ent.get()
tng = [date,km, time]
return tng
def record (self):
tngList = self.listRecord
tngNumber = self.number_ent.get()
datFile = shelve.open(self.fileDat)
datFile[tngNumber] = tngList
#datFile['1'] = tngList
datFile.sync()
datFile.close()
def tngDisplay (self):
tng = ''
self.tngField.delete(0.0, END)
#i=0
datFile = shelve.open(self.fileDat)
for key, item in datFile.items():
tng = str(key) + ': ' + str(item)
# display trainings
self.tngField.insert(0.0, tng)
#i+=1
root = Tk()
root.title('RunForest')
app = Application(root)
root.mainloop()
I have a python assignment to do for University but I am having a problem.The assignment states that I need to create checkbox buttons that have a value that will total once I push a button. This I have managed to do. I have to do the same thing with radio buttons and here I am having a problem. If I create the radio buttons they work, but i do not how to assign a value to them and then use this value in my gandTotal.
`enter code here``#Help with the menu program
import random
from Tkinter import *
class App(Frame):
#GUI application
def __init__(self,master):
Frame.__init__(self,master)
self.grid()
self.create_widgets()
def create_widgets(self):
#Create all the widgets here
#Label to welcome the user
Label(self,text = "Welcome to Awesome Reasturant:"
).grid(row=1,column=0,sticky=W)
#..........your code goes here
#Labels to request the name of the customer
Label(self,text = "Customer Name:"
).grid(row=2,column=0,sticky=W)
self.CustomerName_ent = Entry(self)
self.CustomerName_ent.grid(row = 2, column = 1, sticky = W)
#Labels to request the telephone number
Label(self,text = "Telephone Number:"
).grid(row=3,column=0,sticky=W)
self.Telephone_ent = Entry(self)
self.Telephone_ent.grid(row = 3, column = 1, sticky = W)
#Label to generate a random order number - Nees work
Label(self,text = "Random Order Number:"
).grid(row=3,column=2,sticky=W)
#self.Random_ent = RandomNumber(random.randrange(100))
# Create a label for Starter Menue
Label(self,
text = "Select from starter Menue #R55:"
).grid(row = 7, column = 0, sticky = W)
# create variable for single starter menue item
self.Starter_menue = StringVar()
#create starter menue radio buttons
#Starter_menue = ["Prawn and Muchroom cocktail", "9 Oysters", "Goats cheese"]
#column = 0
#for part in Starter_menue:
# Radiobutton(self,
# text = part,
# variable = self.Starter_menue,
# value = part
# ).grid(row = 9, column = column, sticky = W)
#column += 1
#create radion for Starter item menue 1
Radiobutton(self,text="Prawn and Mushroom",
variable = self.Starter.menue, value = 55, command =self.determine_order
).grid(row=9, column =1, sticky = W)
# Create a label for Starter Menue
Label(self,
text = "Select from Mains Menue #R100:"
).grid(row = 10, column = 0, sticky = W)
# create variable for single mains menue item
self.Mains_menue = StringVar()
#create main course radio buttons
Mains_menue = ["250g Fillet", "Beef Schnitzel", "Chicken", "Quails", "Ravioli", "Genooch"]
column = 0
for part in Mains_menue:
Radiobutton(self,
text = part,
variable = self.Mains_menue,
value = part
).grid(row = 11, column = column, sticky = W)
column += 1
#MENU items to choose from
#I'll do one example with a check button
#the salads
Label(self,text = "Select from Salads"
).grid(row=4,column=0,sticky=W)
self.has_green = BooleanVar()
self.has_blue = BooleanVar()
self.has_ceaser = BooleanVar()
#the greens
Checkbutton(self, text="Greens",
variable=self.has_green
).grid(row=5,column=0,sticky=W)
#the blue salad
Checkbutton(self, text="Blue",
variable=self.has_blue
).grid(row=5,column=1,sticky=W)
#The Ceaser Salad
Checkbutton(self,text="Ceaser Salad",
variable=self.has_ceaser
).grid(row=5,column=2,sticky=W)
#Place the order
Button(self,text = "Place the Order",command = self.determine_order, bg="gold").grid(row = 14, column = 0, sticky = W)
#The display area
self.txt_order = Text(self, width = 75, height = 5, wrap = WORD)
self.txt_order.grid(row = 15, column = 0, columnspan = 4)
def RandomNumber():
RandomNumber = random.randrange(100)
def determine_order(self):
#Get all the information from the GUI
totalprice = 0
totalMain =0
totalStarter =0
grandTotal = totalMain + totalStarter + totalprice
greensaladprice=40
bluesaladprice=40
ceasersaladprice=40
CustomerName =self.CustomerName_ent.get()
Telephone=self.Telephone_ent.get()
Starter_menue = self.Starter_menue.get()
Starter1 = 55
Starter2= 55
Starter3=55
#Check if and which salads are selected
if self.has_green.get():
totalprice = totalprice + greensaladprice
if self.has_blue.get():
totalprice = totalprice + bluesaladprice
if self.has_ceaser.get():
totalprice = totalprice + ceasersaladprice
#Check if and which Starters are selected
if self.Starter_menue(0):
totalStarter = totalStarter + Starter1
if self.Starter_menue(1):
totalStarter = totalStarter + Starter2
if self.Starter.get():
totalStarter = totalStarter + Starter3
#Display the total
self.txt_order.delete(0.0,END)
self.txt_order.insert(0.0,float(grandTotal))
# Add the name -Needs work
self.txt_order.insert(100.50,CustomerName)
#Add telephone number - Needs Work
self.txt_order.insert(0.0,Telephone)
def main():
root = Tk()
root.title("Example - menu 1")
app = App(root)
root.mainloop()
main()
First off, are you missing some code in your example? possibly a Starter initialisation in the App class?
I get a traceback if I try to run:
Traceback (most recent call last):
File "test.py", line 165, in <module>
main()
File "test.py", line 160, in main
app = App(root)
File "test.py", line 10, in __init__
self.create_widgets()
File "test.py", line 57, in create_widgets
variable = self.Starter.menue, value = 55, command =self.determine_order
AttributeError: App instance has no attribute 'Starter'
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.
Basically i've wrote a GUI, to make a maths game and have linked it to my microsft access database using sql, however i cannot get my questions to print to my label, any ideas ?. Also how do you generate a random number from my list of questions, as you can see my jim statement doesnt work.
import Tkinter
import Databaseconnector
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
jim = randomnumber()
SQL = 'SELECT * FROM tblQuestion'
cursor = Databaseconnector.SELECT(SQL)
rows = cursor.fectchall()
for row in rows:
print row.Question, row.Hint, row.A1, row.A2, row.A3, row.A4, row.CorrectAnswer
alabel2.set("Question: " + (row.question)(jim).Item(1))
def create_widgets(self):
# create welcome label
label1 = Tkinter.Label(self, text = "Question Game !")
label1.grid(row = 0, column = 1, columnspan = 2, sticky = 'W')
# create intruction label
alabel2 = Tkinter.Label(self, text = "")
alabel2.grid(row = 1, column = 0, columnspan = 2, sticky = 'W')
a1loginbutton = Tkinter.Button(self, text = "Enter",)
a1loginbutton.grid(row = 9, column = 1, sticky = 'W')
label3 = Tkinter.Label(self, text = "")
label3.grid(row = 10, column = 0, columnspan = 2, sticky = 'W')
a2loginbutton = Tkinter.Button(self, text = "Enter",)
a2loginbutton.grid(row = 11, column = 1, sticky = 'W')
a3loginbutton = Tkinter.Button(self, text = "Enter",)
a3loginbutton.grid(row = 9, column = 3, sticky = 'E')
a4loginbutton = Tkinter.Button(self, text = "Enter",)
a4loginbutton.grid(row = 11, column = 3, sticky = 'E')
label4 = Tkinter.Label(self, text = "")
label4.grid(row = 12, column = 0, columnspan = 2, sticky = 'W')
hiloginbutton = Tkinter.Button(self, text = "Hint",)
hiloginbutton.grid(row = 13, column = 3, sticky = 'E')
label5 = Tkinter.Label(self, text = "Score:")
label5.grid(row = 14, column = 1, columnspan = 5, sticky = 's')
def close_page(self):
self.destroy()
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('my application')
app.geometry("150x200")
app.mainloop()
Edited based on comments from OP:
There is a typo in this line: rows = cursor.fectchall()
Try changing the label.set statement to a simple case to confirm that this works. alabel2.set("Question: " + row.question)
What is the randomnumber() function, and what is the (row.question)(jim).Item(1) line supposed to return?