删除和更改tkinter事件绑定

Sym*_*mon 17 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()
Run Code Online (Sandbox Code Playgroud)

Bry*_*yan 33

您只需bind()使用事件的新功能再次调用即可.既然你没有利用第三个参数,addbind()此只是简单地覆盖任何已经存在.默认情况下,此参数是,''但它也接受"+",这将为已由该事件触发的回调添加回调.

如果您开始使用该可选参数,则需要使用该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>")
Run Code Online (Sandbox Code Playgroud)


arc*_*cra 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)
Run Code Online (Sandbox Code Playgroud)

您需要将其更改为如下所示:

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)
Run Code Online (Sandbox Code Playgroud)

这应该够了吧!


Alb*_*ena 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)
Run Code Online (Sandbox Code Playgroud)

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

myCanvas = tk.Canvas(...)
Run Code Online (Sandbox Code Playgroud)

您将简单地从您的修补版本中实例化它,当且仅当官方来源将被更新和修复时才需要更新:

myCanvas = PatchedCanvas(...)
Run Code Online (Sandbox Code Playgroud)

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