2011-06-21 10 views
14

¿Cómo impido que se procese un evento o cambie qué función se necesita para ello?Eliminación y cambio de un enlace de evento tkinter en python

Código revisado:

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

Respuesta

25

Puede simplemente llamar bind() de nuevo con la nueva función para el evento. Como no está haciendo uso del tercer parámetro, add, en bind(), esto sobrescribirá lo que ya está allí. Por defecto, este parámetro es '', pero también acepta "+", que agregará una devolución de llamada a las devoluciones de llamada ya activadas por ese evento.

Si comienza a usar ese argumento opcional, sin embargo, necesitará usar la función unbind() para eliminar devoluciones de llamada individuales. Cuando llame al bind(), se devuelve funcid. Puede pasar este funcid como el segundo parámetro al unbind().

Ejemplo:

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

Para mí, desatar una sola devolución de llamada no estaba funcionando, pero he encontrado una solución.

Veo que esta es una vieja pregunta, pero para aquellos que, como yo, encontramos esta pregunta cuando enfrentamos el mismo problema, esto es lo que hice para que funcione.

Tendrá que abrir el archivo de origen Tkinter.py y buscar el método de desvinculación de la clase Misc (si está utilizando eclipse es fácil saber la ubicación del archivo y la línea en la que se define esta función presionando Tecla F3 cuando el cursor está sobre una llamada de función .unbind en tu código).

Cuando lo encuentre, debería ver algo como esto:

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) 

Es necesario cambiarlo para buscar somethins así:

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) 

Que debe hacer el truco!

+0

¡Estaba teniendo problemas con la desvinculación también! ¡Debería obtener los cambios fusionados! – timeyyy

+0

@arcra: ejecuta Python 3.5.2 en Ubuntu 16.10 y sigue teniendo el mismo problema que ha solucionado. Su solución aún funciona perfectamente porque la fuente aún no ha sido reparada. Al igual que Arden, le sugiero que lo proponga para obtener el crédito y que definitivamente se aplique. –

4

La respuesta proporcionada por Bryan generalmente funciona bien, pero como arcra ha subrayado, puede que no. Si experimenta el problema de no poder desvincular correctamente una devolución de llamada apilada, modifique la fuente oficial, ¡si sigue siendo la misma! - podría ser una solución.

Aquí siguen mis 2 centavos para aquellos que todavía se encuentran atrapados con el problema: por favor, anule el método unbind(), NO LO EDITEN DIRECTAMENTE.

De esta manera, de hecho, no necesita cambiar manualmente el código fuente oficial en su estación de trabajo (rompiendo así la administración del paquete o reintroduciendo el problema en la próxima actualización del paquete, o teniendo el mismo problema en otro cliente, ...):

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) 

Entonces, en lugar de crear instancias de su widget en su defecto (en mi ejemplo yo uso el lienzo) como esto

myCanvas = tk.Canvas(...) 

simplemente se instanciarlo de su versión parcheada que necesita una actualización si y sólo si se ha actualizado la fuente oficial y fija:

myCanvas = PatchedCanvas(...) 

el método de desvinculación se define actualmente en la clase Varios, de la que hereda BaseWidget y luego, Conseq uenty, Widget, TopLevel, Button, ...

+0

¡Muchas gracias! ¡Necesitaba esto! –

Cuestiones relacionadas