5

我应该如何Toplevel()在 tkinter 中生成父级关闭时不会关闭的子窗口?

我是否需要让父母保留子窗口的“引用计数”,拦截WM_DELETE_WINDOW并仅root.destroy()在所有孩子都走了时才调用?

或者用自己的 tk生成另一个线程mainloop进程是否可以接受?

还是有更优雅的方式?

编辑

我目前正在这样做

root = Tk()
app = App(root) # doesn't call Toplevel()
root.mainloop()

where在不调用的情况下App.__init__()添加小部件,并在某些时候使用此函数生成一个新窗口:rootToplevel()

def new_window():
    root = Tk()
    window = App2(root) # doesn't call Toplevel() either

请注意,rootinnew_window()是与原始变量不同的变量,是root通过对 的另一个调用获得的Tk()

所有这一切似乎都在做正确的事情,即子窗口独立于父窗口而存在,python 进程在两者都关闭后死亡。

所以我的问题变成了,这有意义还是我在这里做错了什么?

4

1 回答 1

1

不必跟踪哪些 Toplevel 处于活动状态,您可以在哨兵上使用弱引用- 只是传递给每个 Toplevel 并保存在引用中的一些对象。当每个 Toplevel 死亡(关闭)时,让它删除其对哨兵的引用。当最后一个对哨兵的引用被删除时,weakref 回调self.no_sentinel将被自动调用,依次root.destroy为你调用。

import Tkinter as tk
import weakref


class Sentinel(object):
    pass


class Window(tk.Toplevel):
    def __init__(self, master, sentinel, **kwargs):
        title = kwargs.pop('title')
        self.sentinel = sentinel
        tk.Toplevel.__init__(self, master, **kwargs)
        self.protocol("WM_DELETE_WINDOW", self.ondelete)
        self.label = tk.Label(self, text=title)
        self.label.pack(padx=10, pady=10)

    def ondelete(self):
        self.destroy()
        del self.sentinel


class App(object):
    def __init__(self, master, **kwargs):
        self.master = master
        sentinel = Sentinel()
        parent = Window(master, sentinel, title='Parent')
        child = Window(master, sentinel, title='Child')
        self._ref = weakref.ref(sentinel, self.no_sentinel)            
        # When we exit `__init__` only two strong references to sentinal
        # remain -- in parent and child. When both strong references are
        # deleted, `self.no_sentinel` gets called.
    def no_sentinel(self, *args):
        self.master.destroy()

root = tk.Tk()
root.withdraw()
app = App(root)
root.mainloop()

或者,您可以使用该multiprocessing模块生成另一个进程来创建另一个 Tkinter 窗口和主循环,但会比上述解决方案消耗更多内存,并且如果您希望单独的进程共享信息,则需要您设置某种形式的进程间通信.

于 2013-06-11T12:54:40.053 回答