How to delete Tkinter widgets from a window?
Asked Answered
D

9

70

I have a list of tkinter widgets that I want to change dynamically.

How to delete the widgets from the window?

Deirdra answered 11/9, 2012 at 7:41 Comment(0)
Y
117

You can call pack_forget to remove a widget (if you use pack to add it to the window).

Example:

from tkinter import *

root = Tk()

b = Button(root, text="Delete me", command=lambda: b.pack_forget())
b.pack()

root.mainloop()

If you use pack_forget, you can later show the widget again calling pack again. If you want to permanently delete it, call destroy on the widget (then you won't be able to re-add it).

If you use the grid method, you can use grid_forget or grid_remove to hide the widget.

Yestreen answered 11/9, 2012 at 7:49 Comment(4)
@TheBeardedBerry: be aware that pack_forget doesn't delete widgets, it only removes them from view. They will still exist, potentially causing a memory leak if you keep recreating widgets without destroying them.Randarandal
If I pack_forget a Frame and then delete it, will it delete the child widgets too, or should I delete them individually?Cannibalize
can you do something like place_forget for place instead of pack?Alundum
@Stegosaurus: Yes, there's also a place_forget() method.Medial
S
26

One way you can do it, is to get the slaves list from the frame that needs to be cleared and destroy or "hide" them according to your needs. To get a clear frame you can do it like this:

from tkinter import *

root = Tk()

def clear():
    list = root.grid_slaves()
    for l in list:
        l.destroy()

Label(root,text='Hello World!').grid(row=0)
Button(root,text='Clear',command=clear).grid(row=1)

root.mainloop()

You should call grid_slaves(), pack_slaves() or slaves() depending on the method you used to add the widget to the frame.

Sgraffito answered 6/7, 2017 at 17:28 Comment(2)
I had 5 buttons in a window. Then I needed to add 3 new buttons and remove old buttons. But 2 old buttons were on the window. With this solution all 5 buttons are removed and only 3 new buttons are added. I use MVP pattern for my app.Magnificent
In the for loop you will need to treat who gets to be deleted and who gets to be removed.Sgraffito
D
5

You simply use the destroy() method to delete the specified widgets like this:

lbl = tk.Label(....)

btn = tk.Button(....., command=lambda: lbl.destroy())

Using this you can completely destroy the specific widgets.

Dunt answered 5/1, 2020 at 17:18 Comment(0)
A
1

You say that you have a list of widgets to change dynamically. Do you want to reuse and reconfigure existing widgets, or create all new widgets and delete the old ones? It affects the answer.

If you want to reuse the existing widgets, just reconfigure them. Or, if you just want to hide some of them temporarily, use the corresponding "forget" method to hide them. If you mapped them with pack() calls, you would hide with pack_forget() (or just forget()) calls. Accordingly, grid_forget() to hide gridded widgets, and place_forget() for placed widgets.

If you do not intend to reuse the widgets, you can destroy them with a straight destroy() call, like widget.destroy(), to free up resources.

Agalloch answered 27/2, 2020 at 1:21 Comment(0)
P
0

clear_btm=Button(master,text="Clear") #this button will delete the widgets 
clear_btm["command"] = lambda one = button1, two = text1, three = entry1: clear(one,two,three) #pass the widgets
clear_btm.pack()

def clear(*widgets):
    for widget in widgets:
        widget.destroy() #finally we are deleting the widgets.
Primine answered 24/6, 2020 at 10:53 Comment(1)
Please add some context or comments to your code so that the author and others can make sense of it easilyNyaya
S
0

You can use the following function if you want to remove widgets based on row and col indexes. Please note that you can choose the method _forget() method based on the layout manager you used.

def remove_widgets_based_on_location(master, rows, cols):
    # list widgets to be removed
    widgets = []
    for row in rows:
        for col in cols:
            l = master.grid_slaves(row, col)
            for i in l:
                widgets.append(i)

    # remove widgets
    for widget in widgets:
        widget.grid_forget()
        # widget.pack_forget()
        # widget.place_forget()

For example, if you want to remove the widgets from the root frame on the frist three rows and first two columns:

remove_widgets_based_on_location(master = root,
                                 rows = [0, 1, 2],
                                 cols = [0, 1])
Styles answered 31/5, 2023 at 7:24 Comment(0)
O
-1

Today I learn some simple and good click event handling using tkinter gui library in python3, which I would like to share inside this thread.

from tkinter import *

cnt = 0


def MsgClick(event):
    children = root.winfo_children()
    for child in children:
        # print("type of widget is : " + str(type(child)))
        if str(type(child)) == "<class 'tkinter.Message'>":
            # print("Here Message widget will destroy")
            child.destroy()
            return

def MsgMotion(event):
  print("Mouse position: (%s %s)" % (event.x, event.y))
  return


def ButtonClick(event):
    global cnt, msg
    cnt += 1
    msg = Message(root, text="you just clicked the button..." + str(cnt) + "...time...")
    msg.config(bg='lightgreen', font=('times', 24, 'italic'))
    msg.bind("<Button-1>", MsgClick)
    msg.bind("<Motion>", MsgMotion)
    msg.pack()
    #print(type(msg)) tkinter.Message


def ButtonDoubleClick(event):
    import sys; sys.exit()


root = Tk()

root.title("My First GUI App in Python")
root.minsize(width=300, height=300)
root.maxsize(width=400, height=350)
button = Button(
    root, text="Click Me!", width=40, height=3
)
button.pack()
button.bind("<Button-1>", ButtonClick)
button.bind("<Double-1>", ButtonDoubleClick)

root.mainloop()

Hope it will help someone...

Overfill answered 26/10, 2017 at 16:8 Comment(2)
is this supposed to be an answer to the question? If not, please remove it. If so, you need to clarify how this relates to deleting a widget.Randarandal
Your code does not answer the question though. You can't just post random things in a thread, because that's not what the thread is for.Foraminifer
R
-1

You can use forget method on the widget

from tkinter import *

root = Tk()

b = Button(root, text="Delete me", command=b.forget)
b.pack()

b['command'] = b.forget

root.mainloop()
Rhizotomy answered 22/5, 2018 at 11:24 Comment(1)
This will raise an error because b isn't defined.Monomerous
P
-2

I found that when the widget is part of a function and the grid_remove is part of another function it does not remove the label. In this example...

def somefunction(self):
    Label(self, text=" ").grid(row = 0, column = 0)
    self.text_ent = Entry(self)
    self.text_ent.grid(row = 1, column = 0)
def someotherfunction(self):
    somefunction.text_ent.grid_remove()

...there is no valid way of removing the Label.

The only solution I could find is to give the label a name and make it global:

def somefunction(self):
    global label
    label = Label(self, text=" ")
    label.grid(row = 0, column = 0)
    self.text_ent = Entry(self)
    self.text_ent.grid(row = 1, column = 0)
def someotherfunction(self):
    global label
    somefunction.text_ent.grid_remove()
    label.grid_remove()

When I ran into this problem there was a class involved, one function being in the class and one not, so I'm not sure the global label lines are really needed in the above.

Phonetics answered 6/6, 2013 at 11:37 Comment(1)
The fact that there is no way to remove the first label you create isn't related to the fact you're creating it in one function and removing it in another, it's simply that you're failing to hold on to a reference. This isn't a tkinter thing, it's a programming thing -- to act on an object you must have a reference to the object. In your second example you don't need to use a global variable. Instead, assign it to self just like you do the entry widget.Randarandal

© 2022 - 2024 — McMap. All rights reserved.