绑定后,绑定会继续存在

时间:2012-10-31 18:57:42

标签: python tkinter

在销毁绑定到外部窗口小部件的窗口时遇到问题。

例如,我有一个根窗口和许多不同的子窗口(在代码中是相同的,以简化它)。

当我从根打开子窗口时。 它创建一个窗口并绑定来自根窗口的信号。 所有子窗口都将绑定到同一个信号,但绑定到不同的回调(每个子窗口一个)。

然后,当我销毁这个子窗口(点击顶角的X)时,绑定仍然存活,这意味着子窗口仍然存活。

问题是: 如何使用绑定销毁子窗口,让其他回调保持活动状态?

在子窗口_destroy方法中,我试过

root.unbind("<<EverybodyDoSomething>>", self.bind1) 

但是我收到了错误

  

TclError:无法删除Tcl命令

如果我使用

root.unbind("<<EverybodyDoSomething>>")

与信号相关的所有回调都被解除绑定。

import Tkinter as Tk

root = Tk.Tk()
i_window = 0

def generate_dosomething_signal():
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail')

def subwindow():
    SubWindow()

class SubWindow(Tk.Tk):
    def __init__(self):
        global i_window
        Tk.Tk.__init__(self)
        self.i = str(i_window)
        i_window += 1
        l = Tk.Label(master=self, text='This is s Sub Window %s!!!!'%self.i)
        l.pack()
        self.bind1 = root.bind('<<EverybodyDoSomething>>', 
                               self.callback_from_sub_window, '+')

        self.bind('<Destroy>', self._destroy)

    def _destroy(self, *args):
#        root.unbind('<<EverybodyDoSomething>>', self.bind1)
#        root.unbind('<<EverybodyDoSomething>>')
        pass

    def callback_from_sub_window(self, *args):
        print 'callback from Sub Window ' + self.i

bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow)
bStartWindow.pack()

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
                                   command = generate_dosomething_signal)
bDoSomethingEverywhere.pack()

root.mainloop()

2 个答案:

答案 0 :(得分:0)

你说的不是Tkinter的正常行为。通常,当您销毁窗口小部件时,其所有子窗口小部件也会被销毁。当它们被摧毁时,它们的绑定就会随之而来。

最有可能的是,问题的根源在于您创建了多个根小部件的实例。你根本做不到这一点。 Tkinter应用程序必须只有一个Tk实例,而且只有一个正在运行的mainloop实例。

如果您需要多个顶级窗口,请为您的第二个和后续窗口创建Toplevel个实例。

此外,您不应该使用bind(...,"+")来完成此任务。正如您所发现的那样,没有办法删除这样的绑定。您可以完全删除<<EverybodyDoSomething>>的所有绑定,但不能仅删除添加了bind(..."+")的部分。

您需要做的是拥有一个调用单个函数的绑定。然后,此函数可以遍历顶层窗口列表,将事件发送到每个窗口。您可以简单地跳过任何不再存在的窗口。您可以使用内省来获取顶层窗口列表,也可以通过在每次代码创建窗口引用时附加窗口引用来手动维护此列表。

答案 1 :(得分:0)

这可以实现你想要的:

import Tkinter as Tk

root = Tk.Tk()
i_window = 0

def generate_dosomething_signal():
    global root
    root.event_generate('<<EverybodyDoSomething>>', when = 'tail')

def subwindow():
    global root
    SubWindow(root)

class SubWindow():
    def __init__(self, root):
        global i_window
        self.root = root

        self.subwindow = Tk.Toplevel()
        self.i = str(i_window)
        self.destroyed = False
        i_window += 1
        l = Tk.Label(master=self.subwindow, text='This is s Sub Window %s!!!!'%self.i)
        l.pack()
        self.bind1 = self.root.bind('<<EverybodyDoSomething>>', 
                               self.callback_from_sub_window, '+')
        self.subwindow.protocol("WM_DELETE_WINDOW", self._destroy)
        #self.subwindow.bind('<Destroy>', self._destroy)

    def _destroy(self, *args):
        self.subwindow.destroy()
        self.destroyed = True
        print "Destroyed ", self.i


    def callback_from_sub_window(self, *args):
        if self.destroyed == False:
            print 'callback from Sub Window ' + self.i


bStartWindow = Tk.Button(master=root, text='Start Sub Window', command=subwindow)
bStartWindow.pack()

bDoSomethingEverywhere = Tk.Button(master=root, text='Do something everywhere', 
                                   command = generate_dosomething_signal)
bDoSomethingEverywhere.pack()

root.mainloop()

最后,他们告诉你,你需要创建subwindows作为toplevels。此外,请注意,每次创建Subwindow()python对象时,它都是指向绑定到&lt; &LT; EverybodyDoSomething&gt; &GT; event然后作为回调附加函数callback_from_sub_window()的本地实例。尽管窗口被破坏(从Tk的角度来看),这种子窗口的Subwindow()对象仍然存在,因此它的callback_from_sub_window()函数。与响应事件的根窗口一样,执行每个创建(和/或销毁)子窗口的“私有”callback_from_sub_window()函数。在Subwindow()类中安装self.destroyed标志可以防止被破坏的子窗口作为回调作出反应。