Skip to main content
 首页 » 编程设计

python之绑定(bind)在销毁后保持事件状态

2025年05月04日10yxwkf

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

例如,我有一个根窗口,和许多不同的子窗口(为了简单起见,代码中是同一个)。

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

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

问题是: 我如何用它的绑定(bind)销毁子窗口,让其他回调保持事件状态?

子窗口中的_destroy方法,我试过了

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

但是我得到一个错误

TclError: can't delete Tcl command

如果我使用

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

所有与信号关联的回调都被解除绑定(bind)。

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

请您参考如下方法:

你说的不是 Tkinter 的正常行为。通常当你销毁一个小部件时,它的所有子部件也会被销毁。当它们被摧毁时,它们的绑定(bind)也会随之消失。

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

如果你想要一个以上的顶层窗口,创建Toplevel的实例对于您的第二个和后续窗口。

另外,你不应该使用 bind(...,"+")来完成这个任务。正如您所发现的,无法删除此类绑定(bind)。您可以完全删除对 <<EverybodyDoSomething>> 的所有绑定(bind), 但你不能只删除一个用 bind(..."+") 添加的部分.

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