Obtener controlador de eventos enlazados en Tkinter
-
02-07-2019 - |
Pregunta
Después de vincular un método a un evento de un elemento Tkinter, ¿hay alguna forma de recuperar el método?
>>> root = Tkinter.Tk()
>>> frame = Tkinter.Frame(root, width=100, height=100)
>>> frame.bind('<Button-1>', lambda e: pprint('Click')) # function needed
>>> frame.pack()
>>> bound_event_method = frame.???
Solución
La llamada asociada para hacer eso para el tk C API sería Get_GetCommandInfo que
coloca información sobre el comando en la estructura Tcl_CmdInfo señalada a por infoPtr
Sin embargo, esta función no se utiliza en ningún lugar en _tkinter.c que es el enlace para tk utilizado por python a través de Tkinter.py .
Por lo tanto, es imposible obtener la función enlazada fuera de tkinter. Necesita recordar esa función usted mismo.
Otros consejos
La forma estándar de hacer esto en Tcl / Tk es trivial: usa el mismo comando de enlace pero sin el argumento final.
bind .b <Button-1> doSomething
puts "the function is [bind .b <Button-1>]"
=> the function is doSomething
Puedes hacer algo similar con Tkinter pero, desafortunadamente, los resultados no son tan fáciles de usar:
e1.bind("<Button-1>",doSomething)
e1.bind("<Button-1>")
=> 'if {"[-1208974516doSomething %# %b %f %h %k %s %t %w %x %y %A %E %K %N %W %T %X %Y %D]" == "break"} break\n'
Obviamente, Tkinter está haciendo muchos malabares debajo de las cubiertas. Una solución sería escribir un pequeño procedimiento de ayuda que lo recuerde:
def bindWidget(widget,event,func=None):
'''Set or retrieve the binding for an event on a widget'''
if not widget.__dict__.has_key("bindings"): widget.bindings=dict()
if func:
widget.bind(event,func)
widget.bindings[event] = func
else:
return(widget.bindings.setdefault(event,None))
Lo usarías así:
e1=Entry()
print "before, binding for <Button-1>: %s" % bindWidget(e1,"<Button-1>")
bindWidget(e1,"<Button-1>",doSomething)
print " after, binding for <Button-1>: %s" % bindWidget(e1,"<Button-1>")
Cuando ejecuto el código anterior, obtengo:
before, binding for <Button-1>: None
after, binding for <Button-1>: <function doSomething at 0xb7f2e79c>
Como advertencia final, no uso mucho Tkinter, así que no estoy seguro de cuáles son las ramificaciones de agregar dinámicamente un atributo a una instancia de widget. Parece ser inofensivo, pero si no, siempre puedes crear un diccionario global para realizar un seguimiento de los enlaces.
No parece ser ... ¿por qué no solo guardarlo si lo vas a necesitar, o usar una función no anónima?
Además, su código no funciona como está escrito: las funciones lambda
solo pueden contener expresiones, no declaraciones, por lo que print
es un no-go (esto cambiará en Python 3.0 cuando print ()
se convierte en una función).