Search code examples
pythontkintertk-toolkitttkwidgets

Cannot remove widget after activating checkbox in Python Tkinter


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.


Solution

  • 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()