Reputation: 3
I am trying to create a menu program in tkinter, where check boxes are created from items in a dictionary, then the total price of selected items is calculated when a button is clicked.
menu_items = {"Spam - £3" : 3, "Eggs - £7" : 7, "Chips - £1" : 1, "Beer - £2" : 2}
def widgets(self):
# create menu list
row = 1
for item in menu_items:
self.item = BooleanVar()
Checkbutton(self,
text = item,
variable = self.item
).grid(row = row, column = 0, sticky = W)
row += 1
calc_but = Button(self,
text = "Click to calculate",
command = self.calculate
).grid(row = row + 1, column = 0, sticky = W)
self.results_txt = Text(self, width = 20, height = 4, wrap = WORD)
self.results_txt.grid(row = row + 2, column = 0, columnspan = 2)
This creates check boxes, button and text display just fine, but my problem comes with my calculate method.
def calculate(self):
bill = 0
for item in menu_items:
if self.item.get():
bill += menu_items.get(item)
msg = "Total cost - £" + str(bill)
self.results_txt.delete(0.0, END)
self.results_txt.insert(0.0, msg)
It will add up everything (ticked or not), but only when the final check box is ticked. It displays 0 if the final item is not ticked.
I am not sure what my problem is, or if I am approaching this in the wrong way.
Upvotes: 0
Views: 1479
Reputation: 584
The way you create your buttons - by looping through each key in you dictionary - your program only references the last one you created, which it saves as self.item
. When you call calculate()
, it only checks and adds up this button's value.
One way around this is to save all the references to these Buttons in a table:
menu_items = {"eggs":7, "chips":1, "beer":2}
selected = {}
def calculate():
bill = 0
for item in menu_items:
if selected[item].get():
bill += menu_items[item]
results.delete(1.0, END)
results.insert(END, "Total cost - £" + str(bill))
for item in menu_items:
is_selected = BooleanVar()
button = Checkbutton(master, text=item, variable=is_selected)
button.grid(sticky="w")
selected[item] = is_selected
purchase_btn = Button(master, text="Calculate", command=calculate)
purchase_btn.grid()
results = Text(master, wrap=WORD)
results.grid(columnspan=2)
(I've omitted your class structure here. It is easy enough to re-incorporate it)
Now we're keeping a is_selected
dictionary, so that we can track whether a button has been selected or not.
Its easy to reference this table, because the keys are the items themselves! Neat, not?
If you're gridding in the next row every time, just call grid()
with no col and row arguments - tkinter adds the row for you, and keeps the column.
It's best always to create a widget, store it as a variable, then grid this variable. Some people try to do this all in one, and then get confused when the try to reference their widget by this variable. They will find nothing, because the grid method returns nothing!
I hope this helped. Good luck!
Upvotes: 4