2

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

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

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

然后,当我销毁这个子窗口(单击右上角的 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()
4

2 回答 2

0

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

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

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

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

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

于 2012-10-31T19:07:42.777 回答
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()

他们明确地告诉您,您需要将子窗口创建为顶层。此外,请注意,每次创建 Subwindow() python 对象时,它都是一个指向绑定到 <<EverybodyDoSomething>> 事件的根窗口的指针,然后作为回调附加函数 callback_from_sub_window() 的本地实例. 尽管窗口已被销毁(从 Tk 的角度来看),但此类子窗口的 Subwindow() 对象仍然存在,因此它的 callback_from_sub_window() 函数仍然存在。作为对事件作出反应的根窗口,去执行每个创建(和/或销毁)子窗口的“私有”回调函数callback_from_sub_window()。在 Subwindow() 类中安装 self.destroyed 标志可以防止被破坏的子窗口作为回调做出反应。

于 2012-10-31T23:46:11.157 回答