Destroying a dynamically created widget

拜拜、爱过 提交于 2019-12-11 10:18:03

问题


I have basically a similar question, though I do not feel it has been answered properly:

Tkinter: How can I dynamically create a widget that can then be destroyed or removed?

The accepted answer is:

You'll want to store the dynamically-created widgets in a list. Have something like

     dynamic_buttons = []

     def onDoubleClick(event):
     ...
     button = Button(...)
     dynamic_buttons.append(button)
     button.pack() 

You can then access the buttons for removal with, say,

     dynamic_buttons[0].destroy()

You can see that the reference they speak of is not variable, here the number 0 is used. But when dynamically creating widgets, how do you connect these references to the buttons?

Say that you create a Toplevel widget (displays a file's content), and want to have a button to close the widget. The dynamic creation will allow multiple files to be open. The problem is that even with this list, how will the button "know" to which widget it belongs, as there is no hard reference (great that you have a list of the items, but toplevel 5 + button 5 have no clue they are 5th in their lists). There will always be just one "active" version of the button and the toplevel, and this one can be deleted.

aanstuur_files = []
aanstuur_frames = []
aanstuur_buttons = []

def editAanstuur():
    openfiles = filedialog.askopenfilenames()
    if not openfiles:
        return 
    for file in openfiles:
        newtop = Toplevel(nGui, height=100, width=100)
        labelTitle = Label(newtop, text=file).pack()
        newButton = Button(newtop, text="save & close", command= ...).pack()
        aanstuur_files.append(file)
        aanstuur_buttons.append(newButton)
        aanstuur_frames.append(newtop)

回答1:


How does the button know which window it belongs to? You tell it:

newButton = Button(newtop, command=lambda top=newtop: top.destroy())

By the way, you're assigning None to newButton in your code. This is because you are doing newbutton = Button(...).pack(), which means newbutton gets the value of pack() which is always None.

If you are going to save a reference to a widget, you must create the widget in a separate step from when you place it in a window.

An even better solution is to take advantage of classes and objects. Create your own subclass of Toplevel, and the instance will keep track of all of the subwidgets for you. For example:

class MyToplevel(Toplevel):
    def __init__(self, parent, filename, *args, **kwargs):
        Toplevel.__init__(self, parent, *args, **kwargs)
        self.filename = filename
        self.savebutton = Button(..., command=self.save)
        ...
    def save(self):
        print "saving...", self.filename
        ...
        self.destroy()
...
openfiles = filedialog.askopenfilenames()
if not openfiles:
    return 
for file in openfiles:
    newtop = MyToplevel(nGui, file, height=100, width=100)



回答2:


APass in a index to your command function using the enumerate() function:

def editAanstuur():
    openfiles = filedialog.askopenfilenames()
    if not openfiles:
        return 
    for i, file in enumerate(openfiles):
        newtop = Toplevel(nGui, height=100, width=100)
        labelTitle = Label(newtop, text=file).pack()
        newButton = Button(newtop, text="Save", command=lambda index=i: print(index)).pack()
        aanstuur_files.append(file)
        aanstuur_buttons.append(newButton)
        aanstuur_frames.append(newtop)

Make sure that you pass the index as a keyword parameter to bind the value when defining the lambda (a closure would use the last value of i).

enumerate() takes a second argument, the index to start at, which defaults at 0.



来源:https://stackoverflow.com/questions/17512297/destroying-a-dynamically-created-widget

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!