I am working on my pet-project. Under the working on GUI part, I faced a problem. I want to add a new widget after clicking the checkbox the first time, and on the second click, this widget should be removed. But in reality, I hav a problem with that. My new widget has been added but not removed. Could you please find the solution yo this issue?
It is my minimum reproducible part of code. The class Window, in initializing, creates TK object as a self.root var and creates a checkbox cb on that. That checkbox has a command self.create_or_delete_new_field, which depends on the status of cb_var, which is Checkbox variable. If cb_var is True, new labek lbl is created on self.root, if False - is deleted.
import tkinter as tk
class Window:
def __init__(self):
# pre-setups window
self.root = tk.Tk()
# checkbox
cb_var = tk.BooleanVar()
cb_var.set(0)
cb = tk.Checkbutton(self.root, text="Checkbox1", onvalue=True, offvalue=False, variable=cb_var,
command=lambda: self.create_or_delete_new_field(cb_var))
cb.grid(row=0, column=0)
self.root.mainloop()
def create_or_delete_new_field(self, cb_var: bool):
lbl = tk.Label(self.root, text=f" Created Label")
if cb_var.get():
lbl.grid(row=0, column=1, sticky='w')
else:
lbl.grid_remove()
app = Window()
I tried not only grid_remove() method but also grid_forget(), destroy(). As I can see the root of problem is deeper than that methods, but my experience cannot find that.
2 Answers 2
Here's a working example. The idea here is to instantiate the Label during Window.__init__() so you're only creating a single label. I've also used Window as the root by inheriting from tk.Tk, since that's common practice. The other trick is using self appropriately to allow the toggle_widget method to access both cb_var and lbl
import tkinter as tk
class Window(tk.Tk):
def __init__(self) -> None:
super().__init__()
self.geometry('400x400')
self.title('Window')
self.cb_var = tk.BooleanVar(self, False) # you can set the initial value here
# NOTE: specifying on/off values isn't strictly necessary
self.cb = tk.Checkbutton(
self,
text='Checkbox1',
variable=self.cb_var,
command=self.toggle_widget,
)
self.cb.grid(row=0, column=0)
self.lbl = tk.Label(self, text='Hello!')
def toggle_widget(self) -> None:
if self.cb_var.get():
self.lbl.grid(row=0, column=1, sticky='w')
else:
self.lbl.grid_forget()
if __name__ == '__main__':
app = Window()
app.mainloop()
Explanation given as comments
import tkinter as tk
class Window(tk.Tk): #make root as argument
def __init__(self):
#Add this line
super().__init__()
self.geometry('200x100')
self.title('Window')
# No need of declaring boolen_variable as we create 2 functions
# Declare self.lbl here and don't pack (or don't add grid)
#There is no need of using f-string
self.lbl = tk.Label(self, text= "Created Label")
self.cb = tk.Checkbutton(self, text="Create Label", command=self.create_lbl)
self.cb.grid(row=0, column=0)
def create_lbl(self):
# pack the lbl here
self.lbl.grid(row=1, column=0, sticky='w')
# Change the text of check button as 'Hide label'
self.cb.configure(text = 'Hide_Label', command = self.hide_lbl)
def hide_lbl(self):
# Use grid_forget to hide label
self.lbl.grid_forget()
# Change the text of check button as 'Create label'
self.cb.configure(text = 'Create Label', command = self.create_lbl)
if __name__ == '__main__':
app = Window()
app.mainloop()
Comments
Explore related questions
See similar questions with these tags.
create_or_delete_new_field(), you create a brand-new Label - and then either make it visible, or leave it invisible. You NEVER do anything with a previous Label, because that value oflblvanished as soon as the function exited. You need forlblto be something persistent - an attribute of your class, or a global variable.