I have a simple tkinter program, where upon clicking a "Create boxes" button, it creates a Checkbutton and a Text widget. I was trying to enable/disable the Text widget based on the Checkbutton. eg- if the Checkbutton is ticked the corresponding Text button will be disabled.
And the following code does work as desired, but I have no idea how? How does a Checkbutton keep track of the corresponding Text widget?
I have tried it with multiple Checkbuttons and they all don't seem to interfere with the other's Text widgets.
from tkinter import *
root = Tk()
root.geometry('500x300')
def create_boxes():
def disable_text():
if textbox['state'] == NORMAL:
textbox['state'] = DISABLED
else:
textbox['state'] = NORMAL
checkbox = Checkbutton(root, command = disable_text)
textbox = Text(root, height= 1, width = 30)
checkbox.pack()
textbox.pack()
create_chechkbutton = Button(root, text= 'Create a checkbox and textbox', command= create_boxes)
create_chechkbutton.pack()
root.mainloop()
Any explanation is appreciated.
CodePudding user response:
The checkbox itself is actually not keeping track of anything. What this code does is binds the checkbox to the disable_text()
function. In effect, this means that disable_text()
is called whenever the checkbox is checked. So, it is actually the function disable_text()
that is keeping track of the text.
When the checkbox is created: checkbox = Checkbutton(root, command = disable_text)
, the disable_text()
function is passed to the command
argument. This tells tkinter to call disable_text()
whenever the checkbutton is pressed.
In disable_text()
, there is an if
statement that checks if the text is disabled. If the text is disabled, disable_text()
enables it. If the text is not disabled, then disable_text()
disables it.
Note that this does not get the state of the checkbox; that is, it does not set the state of the text based on the state of the checkbox: it sets the state of the text based on the state of the text. So, if the text were to start out disabled instead of enabled, the checkbox would be checked when the text was enabled, and unchecked when it wasn't. You could make checkbox
a Button
instead of a Checkbutton
, and it wouldn't make a difference how the code was run.
If there were multiple checkbuttons in your program, each with their own text, the disable_text()
function would have to be bound using the lambda
statement, with an argument telling it which checkbutton was calling it. Here is an example of multiple checkbuttons controlling multiple text widgets:
from tkinter import *
root = Tk()
root.geometry('500x300')
def create_boxes():
def disable_text(checkbox): ### EDITED LINE
textbox = checkbox.textbox ### ADDED LINE
if textbox['state'] == NORMAL:
textbox['state'] = DISABLED
else:
textbox['state'] = NORMAL
for x in range(0, 5): ### ADDED LINE
checkbox = Checkbutton(root)
checkbox.config(command=lambda checkbutton=checkbox: disable_text(checkbutton)) ### EDTIED LINE
textbox = Text(root, height= 1, width = 30)
checkbox.textbox = textbox ### ADDED LINE
checkbox.pack()
textbox.pack()
create_chechkbutton = Button(root, text= 'Create a checkbox and textbox', command=create_boxes)
create_chechkbutton.pack()
root.mainloop()
Using a for
loop, the checkbuttons and text widgets are created and packed. checkbox.textbox = textbox
creates a new attribute of checkbox
, and assigns it to the checkbox, so that that checkbox is associated with that text widget. The line
checkbox.config(command=lambda checkbutton=checkbox: disable_text(checkbutton))
enables the checkbutton to pass itself as an argument to disable_text()
when it calls it. Then, disable_text()
simply gets the text widget associated with the checkbutton it got in its argument, and disables or enables it.