Search code examples
pythonpython-3.xtkinterttk

How can I fix this issue with ttk.Checkbuttons being linked through different variables?


I've been working with Python now for about two weeks. I have come across a situation that I cannot, for the life of me, find a solution for. I'm having an issue with all my checkboxes being linked.

I have searched everywhere and the common thread I'm seeing is that one accidentally doesn't declare distinct variables when declaring the Checkbutton and assigning the variable. But, as you can see in my test code posted below, I have uniquely named variables for each checkbox. As you'll see all variables initialized to FALSE are linked, and all the variables initialized to TRUE are linked.

And while I'm at it, can someone point out why these frames are so screwed up? I'm having a tough time understanding this grid system. Isn't like a regular table that uses row/columns to position stuff? It's now working like that in my experience.

import tkinter
from tkinter import *
from tkinter import ttk, Checkbutton, Tk

checkbox0 = FALSE
checkbox1 = FALSE
checkbox2 = TRUE
checkbox3 = FALSE
checkbox4 = FALSE
checkbox5 = TRUE
checkbox6 = FALSE
checkbox7 = FALSE
checkbox8 = TRUE
checkbox9 = FALSE

mainWindow = Tk()

maincontent = ttk.Frame(mainWindow, borderwidth=5, relief='sunken', width=600, height=400).grid(row=0, column=0, padx=5, pady=5, sticky=NSEW)
content0 = ttk.Frame(maincontent, borderwidth=5, relief='sunken').grid(row=0, column=0, sticky=NSEW)
checkbox_0 = ttk.Checkbutton(content0, text="Checkbox 0", variable=checkbox0).grid(row=0, column=0, padx=5, pady=5)
checkbox_1 = ttk.Checkbutton(content0, text="Checkbox 1", variable=checkbox1).grid(row=1, column=0, padx=5, pady=5)
checkbox_2 = ttk.Checkbutton(content0, text="Checkbox 2", variable=checkbox2).grid(row=2, column=0, padx=5, pady=5)
checkbox_3 = ttk.Checkbutton(content0, text="Checkbox 3", variable=checkbox3).grid(row=3, column=0, padx=5, pady=5)
checkbox_4 = ttk.Checkbutton(content0, text="Checkbox 4", variable=checkbox4).grid(row=4, column=0, padx=5, pady=5)

content1 = ttk.Frame(maincontent, borderwidth=5, relief='sunken').grid(row=0, column=1, sticky=NSEW)
checkbox_5 = ttk.Checkbutton(content1, text="Checkbox 5", variable=checkbox5).grid(row=0, column=0, padx=5, pady=5)
checkbox_6 = ttk.Checkbutton(content1, text="Checkbox 6", variable=checkbox6).grid(row=1, column=0, padx=5, pady=5)
checkbox_7 = ttk.Checkbutton(content1, text="Checkbox 7", variable=checkbox7).grid(row=2, column=0, padx=5, pady=5)
checkbox_8 = ttk.Checkbutton(content1, text="Checkbox 8", variable=checkbox8).grid(row=3, column=0, padx=5, pady=5)
checkbox_9 = ttk.Checkbutton(content1, text="Checkbox 9", variable=checkbox9).grid(row=4, column=0, padx=5, pady=5)


mainWindow.mainloop()

I would greatly appreciate someone explaining what is happening here and how to make this work correctly. I could just have overload from working on my project nearly non-stop for the past two weeks.

Thanks for any help anyone can provide.


Solution

  • There are two major things wrong with your code. Firstly, Checkbutton expects a Tkinter variable, which is BooleanVar, StringVar, DoubleVar or IntVar. So all the variables you created are not applicable for the Checkbutton.

    Next, you repeatedly did something like maincontent=ttk.Frame(....).grid(...). This returns None and then it got assigned to your variable maincontent. To properly hold a reference to each widget, you need to split it into two lines:

    maincontent=ttk.Frame(...)
    maincontent=grid(...)
    

    With both things fixed, here is how your code can work by using for loop to reduce repeating code:

    import tkinter as tk
    from tkinter import ttk
    
    mainWindow = tk.Tk()
    
    all_var = [tk.BooleanVar() for _ in range(10)]
    
    maincontent = ttk.Frame(mainWindow, borderwidth=5, relief='sunken', width=600, height=400)
    maincontent.grid(row=0, column=0, padx=5, pady=5, sticky="nsew")
    content0 = ttk.Frame(maincontent, borderwidth=5, relief='sunken')
    content0.grid(row=0, column=0, sticky="nsew")
    content1 = ttk.Frame(maincontent, borderwidth=5, relief='sunken')
    content1.grid(row=0, column=1, sticky="nsew")
    
    for i in range(5):
        ttk.Checkbutton(content0, text=f"Checkbox {i}",variable=all_var[i],
                        command=lambda x=i: print(f"Checkbox {x}, {all_var[x].get()}")
                        ).grid(row=i, column=0, padx=5, pady=5)
        ttk.Checkbutton(content1, text=f"Checkbox {i+5}", variable=all_var[i+5],
                        command=lambda x=i+5: print(f"Checkbox {x}, {all_var[x].get()}")
                        ).grid(row=i, column=0, padx=5, pady=5)
    
    mainWindow.mainloop()