As @Henry Yik said, you shouldn't recreate all the checkbuttons every time you want to show them; 1) because it's easier to write that doesn't recreate them, and 2) because code that does recreate them will be much slower than code that doesn't.
As usual, I'll explain everything, but if you want to skip the explanations, at the bottom will be a (minimalized) working example.
Creating the checkbuttons
First, in order to make it so that the checkbuttons can be packed and pack_forgotten, they need to be created. For your purposes, it's simplest to use a for
loop to create the checkbuttons, and then add them to a list. Here's an example for creating the perishable checkbuttons:
self.perishables = []
for i in PERISHABLE_OPTIONS:
PERISHABLE_OPTIONS[i] = tk.IntVar()
checkbutton = tk.Checkbutton(self, text=i, variable=PERISHABLE_OPTIONS[i])
self.perishables.append(checkbutton)
As you can see, this simply loops through all the keys in PERISHABLE_OPTIONS
, and creates checkbuttons based on them, in much the same way as you did in your code. The only difference is that the checkbuttons are stored in a list called self.perishables
for later use. You can do the same for the non-perishable checkbuttons.
Packing/unpacking the checkbuttons
Now that you've created a list for each type of checkbutton, you need to know how to pack/unpack them. We'll do that by checking which radio button is selected (which you've already done), and then:
- Looping through the checkbuttons of the not-selected radiobutton and calling their
pack_forget()
method.
- Looping through the checkbuttons of the selected radiobutton and calling their
pack()
method, with the appropriate arguments.
Here is an example that does just that, unpacking the non-perishable checkbuttons and packing the perishable checkbuttons:
def show_checkbox(self, v):
"""Show the checkboxes for selected radio button NUMBER."""
# Show the perishables
if v.get() == "1":
for c in self.nonperishables:
c.pack_forget()
for c in self.perishables:
c.pack(anchor="center", padx=5, pady=5)
# Or show the non-perishables
if v.get() == "2":
for c in self.perishables:
c.pack_forget()
for c in self.nonperishables:
c.pack(anchor="center", padx=5, pady=5)
Showing the checkbuttons when the app starts
You might notice that, when the app starts, neither radiobutton will be selected, so neither list of checkbuttons will be shown. We can solve both these problems simultaneously by setting an initial value for the radiobuttons' var
, like this:
category_of_donation = {"Perishable": "1", "Non-Perishable": "2"}
var = tk.StringVar(value="1")
for text, value in category_of_donation.items():
r = tk.Radiobutton(self, text=text, variable=var, value=value, command=lambda: self.show_checkbox(var))
r.pack(anchor="center", padx=5, pady=5)
This code will have the perishables selected first. If you want to show the non-perishables first, just change tk.StringVar(value="1")
to tk.StringVar(value="2")
.
The final code
Alright, now that all that's said, here is a simplified working example based off of your code:
import tkinter as tk
PERISHABLE_OPTIONS = {'Vegetables': 0, 'Fruits': 0, 'Bread': 0, 'Dairy': 0, 'Meat': 0, 'Other': 0}
NONPERISHABLE_OPTIONS = {'Books': 0, 'Clothes': 0, 'Dry Food': 0, 'Household': 0, 'Sanitary': 0, 'Other': 0}
class Frame(tk.Frame):
"""The frame that has all the checkbuttons."""
def __init__(self, master):
tk.Frame.__init__(self, master=master)
# Create the label
label = tk.Label(self, text="Choose your donations!")
label.pack(side="top", fill="x", pady=10)
# Create the radiobuttons
category_of_donation = {"Perishable": "1", "Non-Perishable": "2"}
var = tk.StringVar(value="1")
for text, value in category_of_donation.items():
r = tk.Radiobutton(self, text=text, variable=var, value=value, command=lambda: self.show_checkbox(var))
r.pack(anchor="center", padx=5, pady=5)
# Create the submit button (doesn't do anything here)
tk.Button(self, text="Submit").pack()
# Create the checkbuttons
self.perishables = []
for i in PERISHABLE_OPTIONS:
PERISHABLE_OPTIONS[i] = tk.IntVar()
checkbutton = tk.Checkbutton(self, text=i, variable=PERISHABLE_OPTIONS[i])
self.perishables.append(checkbutton)
# Create the checkbuttons
self.nonperishables = []
for i in NONPERISHABLE_OPTIONS:
NONPERISHABLE_OPTIONS[i] = tk.IntVar()
checkbutton = tk.Checkbutton(self, text=i, variable=NONPERISHABLE_OPTIONS[i])
self.nonperishables.append(checkbutton)
# Show the perishabe checkbuttons
self.show_checkbox(var)
def show_checkbox(self, v):
"""Show the checkboxes for selected radio button NUMBER."""
# Show the perishables
if v.get() == "1":
for c in self.nonperishables:
c.pack_forget()
for c in self.perishables:
c.pack(anchor="center", padx=5, pady=5)
# Or show the non-perishables
if v.get() == "2":
for c in self.perishables:
c.pack_forget()
for c in self.nonperishables:
c.pack(anchor="center", padx=5, pady=5)
if __name__ == "__main__":
root = tk.Tk()
frame = Frame(root)
frame.pack(expand=True, fill="both")
root.mainloop()