使tkinter toplevel窗口不与父关闭

时间:2013-06-11 11:47:13

标签: python tkinter

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

我是否需要父母保留子窗口的“引用计数”,拦截WM_DELETE_WINDOW并且只有在所有孩子都离开后才调用root.destroy()

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

或者有更优雅的方式吗?

修改

我目前正在以这种方式做事

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

其中App.__init__()在不调用root的情况下向Toplevel()添加小部件,并在某个时刻生成一个具有此功能的新窗口:

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

请注意root中的new_window()与原始root的变量不同,是通过另一次调用Tk()获得的。

所有这些似乎都是正确的事情,即子窗口独立于父窗口,并且python进程在两者关闭后都会死亡。

所以我的问题变成了,这是否有意义,或者我在这里做了一些可怕的错误?

1 个答案:

答案 0 :(得分:1)

您无需跟踪哪些Toplevels活着,您可以在哨兵上使用weakref - 只是传递给每个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窗口和mainloop,但是消费者会比上面的解决方案更多的内存,并且需要你如果您希望单独的进程共享信息,请设置某种形式的进程间通信。