Hallam Barwick
Hallam Barwick

Reputation: 3

How to use a dictionary to create tkinter check boxes, then check which are ticked

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

Answers (1)

EriktheRed
EriktheRed

Reputation: 584

What's happening here

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?

A couple more tips on tkinter:

  • 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

Related Questions