删除和更改tkinter事件绑定

时间:2011-06-21 23:54:05

标签: python events tkinter

如何停止处理事件或切换为其调用的函数?

修订代码:

from Tkinter import *

class GUI:
    def __init__(self,root):
        Window = Frame(root)
        self.DrawArea = Canvas(Window)
        self.DrawArea.pack()
        Window.pack()

        self.DrawArea.bind("<Button 1>",self.starttracking)

    def updatetracking(self,event):
        print event.x,event.y

    def finishtracking(self,event):
        self.DrawArea.bind("<Button 1>",self.starttracking)
        self.DrawArea.unbind("<Motion>")

    def starttracking(self,event):
        print event.x,event.y
        self.DrawArea.bind("<Motion>",self.updatetracking)
        self.DrawArea.bind("<Button 1>",self.finishtracking)



if __name__ == '__main__':
    root = Tk()
    App = GUI(root)
    root.mainloop()

3 个答案:

答案 0 :(得分:31)

您只需使用事件的新功能再次呼叫bind()即可。由于您没有在add中使用第三个参数bind(),因此这将覆盖已存在的任何内容。默认情况下,此参数为'',但它也接受"+",这将为已由该事件触发的回调添加回调。

如果您开始使用该可选参数,则需要使用unbind()函数删除单个回调。当您致电bind()时,会返回funcid。您可以将此funcid作为第二个参数传递给unbind()

示例:

self.btn_funcid = self.DrawArea.bind("<Button 1>", self.my_button_callback, "+")

# Then some time later, to remove just the 'my_button_callback':
self.DrawArea.unbind("<Button 1>", self.btn_funcid)

# But if you want to remove all of the callbacks for the event:
self.DrawArea.unbind("<Button 1>")

答案 1 :(得分:5)

对我来说,取消绑定单个回调不起作用,但我找到了解决方案。

我可以看到这是一个老问题,但对于那些像我一样在遇到同样问题时找到这个问题的人,这就是我为使其发挥作用而做的。

您将需要打开源文件Tkinter.py并搜索Misc类的unbind方法(如果您使用的是eclipse,通过按F3可以很容易地知道文件的位置和定义此函数的行当光标位于代码中的.unbind函数调用时键。

当你找到它时,你应该看到这样的东西:

def unbind(self, sequence, funcid=None):
        """Unbind for this widget for event SEQUENCE  the
        function identified with FUNCID."""
        self.tk.call('bind', self._w, sequence, '')
        if funcid:
            self.deletecommand(funcid)

你需要改变它看起来像这样的东西:

def unbind(self, sequence, funcid=None):
        """Unbind for this widget for event SEQUENCE  the
        function identified with FUNCID."""
    if not funcid:
        self.tk.call('bind', self._w, sequence, '')
        return
    func_callbacks = self.tk.call('bind', self._w, sequence, None).split('\n')
    new_callbacks = [l for l in func_callbacks if l[6:6 + len(funcid)] != funcid]
    self.tk.call('bind', self._w, sequence, '\n'.join(new_callbacks))
    self.deletecommand(funcid)

这应该可以做到!

答案 2 :(得分:5)

布莱恩提供的答案通常效果很好,但正如arcra强调的那样,它可能没有。如果您遇到无法正确取消绑定堆叠回调的问题,请修改官方来源 - 如果它仍然相同! - 可能是一个解决方案。

对于那些仍然发现自己遇到问题的人,请遵循我的2美分:请覆盖unbind()方法,不要直接编辑。

事实上,这样一来,您无需手动更改工作站上的官方源代码(从而破坏软件包管理,或在下一次软件包更新时重新引入问题,或在其他客户端上出现相同问题)。 ..):

import tkinter as tk


class PatchedCanvas(tk.Canvas):
    def unbind(self, sequence, funcid=None):
        '''
        See:
            http://stackoverflow.com/questions/6433369/
            deleting-and-changing-a-tkinter-event-binding-in-python
        '''

        if not funcid:
            self.tk.call('bind', self._w, sequence, '')
            return
        func_callbacks = self.tk.call(
            'bind', self._w, sequence, None).split('\n')
        new_callbacks = [
            l for l in func_callbacks if l[6:6 + len(funcid)] != funcid]
        self.tk.call('bind', self._w, sequence, '\n'.join(new_callbacks))
        self.deletecommand(funcid)

然后,而不是像这样实例化你失败的小部件(在我的例子中,我使用Canvas)

myCanvas = tk.Canvas(...)

只需在官方来源更新和修复的情况下,您只需从修补后的版本中对其进行实例化即可进行更新:

myCanvas = PatchedCanvas(...)

unbind方法目前在Misc类中定义,BaseWidget从该类继承它,然后,结果,Widget,TopLevel,Button,......