4

I'm currently trying to create a GUI to compare files between two different folders and have a rudimentary framework that I'm trying to build off of right now.

I have three frames on the left, right, and bottom of the window with two checkbuttons each. I want to be able to select each checkbutton independently of each other but every time I click on the first checkbutton of any one of the frames, the first checkbutton for the other frames also selects/deselects at the same time.

Why is this the case, and how do I make them work independently from each other? Here's my code for reference:

from tkinter import *

root = Tk()

leftFrame = Frame(root, bg = "#4d94ff")
leftFrame.pack(side = LEFT, fill = BOTH)

rightFrame = Frame(root, bg = "#ff4d4d")
rightFrame.pack(side = RIGHT, fill = BOTH)

bottomFrame = Frame(root, bg = "#5cd65c")
bottomFrame.pack(side = BOTTOM)

check_L1 = Checkbutton(leftFrame, text = "C1", bg = "#4d94ff")
check_L2 = Checkbutton(leftFrame, text = "C2", bg = "#4d94ff")

check_R1 = Checkbutton(rightFrame, text = "C1", bg = "#ff4d4d")
check_R2 = Checkbutton(rightFrame, text = "C2", bg = "#ff4d4d")

checktype1 = Checkbutton(bottomFrame, text = "Check Type 1", bg = "#5cd65c")
checktype2 = Checkbutton(bottomFrame, text = "Check Type 2", bg = "#5cd65c")

check_L1.grid(row = 0)
check_L2.grid(row = 0, column = 1)
check_R1.grid(row = 0)
check_R2.grid(row = 0, column = 1)
checktype1.grid(row = 0)
checktype2.grid(row = 1)


root.mainloop()
  • 1
    I ran your code in python 2.7.15 on OSX and did not experience this issue — i could check and uncheck all the checkboxes independently. – Personman Nov 14 '19 at 19:58
  • Interesting, I'm experiencing this issue on Python 3.7.4 on Windows 10. Might be a compatibility issue or some kind of bug? – Dalton Trinh Nov 14 '19 at 20:28
  • Honestly does sound like it could be a bug in p3 tkinter?? I guess you could try reporting it if that sounds fun. – Personman Nov 14 '19 at 21:16

2 Answers2

6

TL;DR

You need to specify a unique variable with each checkbutton.

var_L1 = tk.IntVar()
var_R1 = tk.IntVar()
...
check_L1 = Checkbutton(..., variable=var_L1)
check_R1 = Checkbutton(..., variable=var_R1)
...

What is happening

Checkbuttons require a variable to be associated with them. You are't explicitly setting a variable so tkinter is creating defaults. Tkinter does this by creating internal variables named after the checkbutton name.

When you create widgets and don't give them names, tkinter will pick default names. The full name includes the names of entire widget hierarchy. So, for example, the internal name for check_L1 is .!frame.!checkbutton', the name for check_R1 is .!frame2.!checkbutton, and the internal name for checktype1 is '.!frame3.!checkbutton'.

When tkinter creates the default variables for the checkbuttons it uses only the last component of the full name for the variables. Thus, for check_L1 it creates an internal variable named !checkbutton. The internal variable for check_R1 is also !checkbutton, as is the internal variable for checktype2.

Because all of these checkbuttons share the same internal variable, they are linked.


Note: if you are creating a lot of checkboxes in a loop, you can save the reference to each checkbutton in an array. For example:

vars = []
for i in range(x):
    vars.append[tk.IntVar())
...
check_L1 = Checkbutton(..., variable=vars[0])
...
print(f"the value of L1 is {vars[0].get()}")
Bryan Oakley
  • 370,779
  • 53
  • 539
  • 685
2

I'm not sure why this happens, but you can make checkbuttons independent by associating them with a variable:

from tkinter import *

root = Tk()

leftFrame = Frame(root, bg = "#4d94ff")
leftFrame.pack(side = LEFT, fill = BOTH)

rightFrame = Frame(root, bg = "#ff4d4d")
rightFrame.pack(side = RIGHT, fill = BOTH)

bottomFrame = Frame(root, bg = "#5cd65c")
bottomFrame.pack(side = BOTTOM)

check_L1 = Checkbutton(leftFrame, text = "C1", bg = "#4d94ff", variable=IntVar())
check_L2 = Checkbutton(leftFrame, text = "C2", bg = "#4d94ff", variable=IntVar())

check_R1 = Checkbutton(rightFrame, text = "C1", bg = "#ff4d4d", variable=IntVar())
check_R2 = Checkbutton(rightFrame, text = "C2", bg = "#ff4d4d", variable=IntVar())

checktype1 = Checkbutton(bottomFrame, text = "Check Type 1", bg = "#5cd65c", variable=IntVar())
checktype2 = Checkbutton(bottomFrame, text = "Check Type 2", bg = "#5cd65c", variable=IntVar())

check_L1.grid(row = 0)
check_L2.grid(row = 0, column = 1)
check_R1.grid(row = 0)
check_R2.grid(row = 0, column = 1)
checktype1.grid(row = 0)
checktype2.grid(row = 1)


root.mainloop()


Maximouse
  • 4,170
  • 1
  • 14
  • 28
  • Awesome, this worked out. I'll try to see why this fixes it but for now as long as it works I'm happy with it. Thank you! – Dalton Trinh Nov 14 '19 at 20:30