Подтвердить что ты не робот

Удаление и изменение привязки события tkinter в 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()
4b9b3361

Ответ 1

Вы можете просто просто вызвать 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>")

Ответ 2

Для меня отключение одного обратного вызова не работало, но я нашел решение.

Я вижу, что это старый вопрос, но для тех, кто, как и я, находит этот вопрос, столкнувшись с одной и той же проблемой, это то, что я сделал, чтобы заставить его работать.

Вам нужно будет открыть исходный файл Tkinter.py и выполнить поиск метода unbind класса Misc (если вы используете 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)

Это должно сделать трюк!

Ответ 3

Ответ, предоставленный Брайаном, как правило, хорошо работает, но, как подчеркнула arcra, это может и не быть. Если вы столкнулись с проблемой неспособности правильно развязать сложный обратный вызов, изменив официальный источник - если он все тот же! - может быть решением.

Здесь следуют мои 2 цента для тех, кто все еще сталкивается с проблемой: пожалуйста, переопределите метод unbind(), НЕ РЕДАЙТЕ ЭТО ПРЯМО.

Таким образом, на самом деле вам не нужно вручную изменять официальный исходный код на вашей рабочей станции (таким образом, нарушая управление пакетами или повторно вводить проблему при следующем обновлении пакета или имея ту же проблему на другом клиенте...):

import tkinter as tk


class PatchedCanvas(tk.Canvas):
    def unbind(self, sequence, funcid=None):
        '''
        See:
            http://stackoverflow.com/info/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,...