2011-06-21 6 views
14

Comment arrêter un traitement d'un événement ou changer la fonction qui lui est demandée?Suppression et modification d'une liaison d'événement tkinter dans python

Revised Code:

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

Répondre

25

Vous pouvez tout simplement appeler bind() à nouveau avec la nouvelle fonction pour l'événement. Puisque vous n'utilisez pas le troisième paramètre, add, dans bind() cela remplacera juste ce qui est déjà là. Par défaut, ce paramètre est '' mais il accepte également "+", ce qui ajoutera un rappel aux rappels déjà déclenchés par cet événement.

Si vous commencez à utiliser cet argument facultatif, vous devrez utiliser la fonction unbind() pour supprimer les rappels individuels. Lorsque vous appelez bind(), un funcid est renvoyé. Vous pouvez passer ce funcid comme deuxième paramètre à unbind().

Exemple:

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>") 
4

Pour moi, déliant un seul rappel ne fonctionnait pas, mais je l'ai trouvé une solution.

Je peux voir que c'est une vieille question, mais pour ceux qui, comme moi, trouvent cette question face au même problème, voici ce que j'ai fait pour le faire fonctionner.

Vous devrez ouvrir le fichier source Tkinter.py et rechercher la méthode unbind de la classe Misc (si vous utilisez eclipse, il est facile de connaître l'emplacement du fichier et la ligne dans laquelle cette fonction est définie en appuyant sur Touche F3 lorsque le curseur est sur un appel de fonction .unbind dans votre code).

Lorsque vous trouvez, vous devriez voir quelque chose comme ceci:

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) 

Vous devez changer pour regarder somethins comme ceci:

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) 

Cela devrait faire l'affaire!

+0

J'avais des problèmes avec unbind aussi! Vous devriez obtenir les changements fusionnés! – timeyyy

+0

@arcra: Exécuter Python 3.5.2 sur Ubuntu 16.10 et avoir toujours le même problème que vous avez corrigé. Votre solution fonctionne toujours parfaitement car la source n'a pas encore été corrigée. Comme Arden je vous suggère de le proposer afin d'obtenir le crédit et l'avoir définitivement appliqué. –

4

La réponse fournie par Bryan fonctionne généralement bien, mais comme arcra l'a souligné, ce n'est peut-être pas le cas. Si vous rencontrez le problème de ne pas être en mesure de déconnecter correctement un rappel empilé, en modifiant la source officielle - si elle est toujours la même! - pourrait être une solution.

Voici mes 2 cents pour ceux qui se retrouvent encore avec le problème: s'il vous plaît, remplacer la méthode unbind(), NE PAS EDIT DIRECTEMENT. De cette façon, en fait, vous n'avez pas besoin de changer manuellement le code source officiel sur votre poste de travail (ce qui interrompt la gestion des paquets, ou réintroduit le problème lors de la prochaine mise à jour, ou le même problème sur un autre client, ...):

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) 

Ensuite, au lieu d'instancier votre widget ne (dans mon exemple, j'utilise la toile) comme celui-ci

myCanvas = tk.Canvas(...) 

vous simplement instancier à partir de votre version patchée qui aura besoin d'une mise à jour si et seulement si la source officielle sera mise à jour et fixe:

myCanvas = PatchedCanvas(...) 

la méthode unbind est actuellement définie dans la classe Misc, dont BaseWidget hérite puis, CONSEQ uenty, Widget, TopLevel, bouton, ...

+0

Merci beaucoup! J'avais besoin de ça! –