删除和更改tkinter事件绑定

2024-05-13 17:30:16 发布

您现在位置:Python中文网/ 问答频道 /正文

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

修订代码:

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

Tags: selfeventbinddefguibuttonrootwindow
3条回答

您只需使用事件的新函数再次调用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>")

布莱恩提供的答案通常很有效,但正如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)

然后,不要像这样实例化失败的小部件(在我的示例中,我使用画布)

myCanvas = tk.Canvas(...)

您只需从补丁版本中实例化它,如果且仅当官方源将被更新和修复时,该版本将需要更新:

myCanvas = PatchedCanvas(...)

unbind方法当前是在Misc类中定义的,BaseWidget从中继承它,然后,结果地,Widget,TopLevel,Button。。。

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

我可以看出这是一个老问题,但对于那些像我自己一样,在面对同样的问题时发现这个问题的人来说,这就是我所做的使之奏效的事情。

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

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

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)

这应该是个好办法!

相关问题 更多 >