【问题标题】:How to delete Tkinter widgets from a window?如何从窗口中删除 Tkinter 小部件?
【发布时间】:2012-09-04 02:30:11
【问题描述】:

我有一个想要动态更改的tkinter 小部件列表。

如何从窗口中删除小部件?

【问题讨论】:

    标签: python tkinter


    【解决方案1】:

    您可以调用pack_forget 来移除一个小部件(如果您使用pack 将它添加到窗口中)。

    例子:

    from tkinter import *
    
    root = Tk()
    
    b = Button(root, text="Delete me", command=lambda: b.pack_forget())
    b.pack()
    
    root.mainloop()
    

    如果您使用pack_forget,您可以稍后再次显示小部件,再次调用pack。如果您想永久删除它,请在小部件上调用destroy(然后您将无法重新添加它)。

    如果您使用grid 方法,您可以使用grid_forgetgrid_remove隐藏小部件。

    【讨论】:

    • @TheBeardedBerry:请注意pack_forget 不会删除小部件,它只会将它们从视图中删除。它们仍然存在,如果您继续重新创建小部件而不破坏它们,可能会导致内存泄漏。
    • 如果我pack_forget一个Frame然后删除它,它是否也会删除子小部件,还是应该单独删除它们?
    • 你能用place_forget代替包装吗?
    • @Stegosaurus:是的,还有一个place_forget()方法。
    【解决方案2】:

    您可以做到这一点的一种方法是从需要清除的框架中​​获取从属列表,并根据您的需要销毁或“隐藏”它们。要获得清晰的框架,您可以这样做:

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

    您应该调用grid_slaves()pack_slaves()slaves(),具体取决于您用于将小部件添加到框架的方法。

    【讨论】:

    • 我在一个窗口中有 5 个按钮。然后我需要添加 3 个新按钮并删除旧按钮。但是窗户上有两个旧按钮。使用此解决方案,所有 5 个按钮都被删除,只添加了 3 个新按钮。我在我的应用中使用 MVP 模式。
    • 在 for 循环中,您需要处理谁将被删除以及谁将被删除。
    【解决方案3】:

    您只需使用destroy() 方法删除指定的小部件,如下所示:

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

    使用它可以完全销毁特定的小部件。

    【讨论】:

      【解决方案4】:

      您说您有一个要动态更改的小部件列表。您想重用和重新配置现有的小部件,还是创建所有新的小部件并删除旧的小部件?它会影响答案。

      如果您想重用现有的小部件,只需重新配置它们。或者,如果你只是想暂时隐藏其中的一些,使用相应的“忘记”方法来隐藏它们。如果您使用pack() 调用映射它们,您将使用pack_forget()(或只是forget())调用隐藏。因此,grid_forget() 隐藏网格小部件,place_forget() 用于放置小部件。

      如果您不打算重复使用这些小部件,您可以直接使用destroy() 调用(例如widget.destroy())来销毁它们,以释放资源。

      【讨论】:

        【解决方案5】:

        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.
        

        【讨论】:

        • 请在您的代码中添加一些上下文或 cmets,以便作者和其他人可以轻松理解它
        【解决方案6】:

        今天我在python3中使用tkinter gui库学习了一些简单而好的点击事件处理,我想在这个线程中分享。

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

        希望对某人有所帮助...

        【讨论】:

        • 这应该是问题的答案吗?如果没有,请删除它。如果是这样,您需要澄清这与删除小部件有何关系。
        • 您的代码并没有回答这个问题。您不能只是在线程中发布随机的东西,因为这不是线程的目的。
        【解决方案7】:

        您可以在小部件上使用忘记方法

        from tkinter import *
        
        root = Tk()
        
        b = Button(root, text="Delete me", command=b.forget)
        b.pack()
        
        b['command'] = b.forget
        
        root.mainloop()
        

        【讨论】:

        • 这将引发错误,因为b 未定义。
        【解决方案8】:

        我发现当小部件是函数的一部分并且grid_remove 是另一个函数的一部分时,它不会删除标签。在这个例子中......

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

        ...没有删除标签的有效方法。

        我能找到的唯一解决方案是为标签命名并使其全局化:

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

        当我遇到这个问题时,涉及到一个类,一个函数在类中,一个不在,所以我不确定上面是否真的需要 global label 行。

        【讨论】:

        • 无法删除您创建的第一个标签这一事实与您在一个函数中创建它并在另一个函数中删除它的事实无关,只是您失败了坚持参考。这不是 tkinter 的事情,而是编程的事情——要作用于一个对象,你必须有一个对该对象的引用。在您的第二个示例中,您不需要使用全局变量。相反,将其分配给self,就像您执行条目小部件一样。