En Tkinter, tengo varios widgets enlazados al botón izquierdo del ratón. Todos activan el mismo evento cuando se hace clic.
¿Cómo recupero en qué widget se hizo clic?
Lo quiero así que cuando digamos que se presionó Label2
, podría recuperar que Label2
era el widget que se presionó en el evento que se activó.
def f(event): caller = event.widget
Usted tiene un par de opciones. Una forma es acceder al atributo del widget
del objeto de evento. Otra forma es pasar una referencia de objeto a su función. Aquí hay un ejemplo que usa uno de cada uno.
import Tkinter as tk def OnClickA(event): print "you clicked on", event.widget event.widget.config(text="Thank you!") def OnClickB(event, obj): print "you clicked on", obj obj.config(text="Thank you!") root = tk.Tk() l1 = tk.Label(root, text="Click me") l2 = tk.Label(root, text="No, click me!") l1.pack() l2.pack() l1.bind("<1>", OnClickA) l2.bind("<1>", lambda event, obj=l2: OnClickB(event, obj)) root.mainloop()
Parece que todos tus widgets están compartiendo un controlador de eventos. Este extracto de la referencia Tkinter 8.4 de John W. Shipman – NM Tech, puede ayudar.
30.7. El truco de argumentos extra
A veces, le gustaría pasar otros argumentos a un controlador además del evento.
Aquí hay un ejemplo. Supongamos que su aplicación tiene una matriz de diez botones de verificación cuyos widgets se almacenan en una lista
self.cbList
, indexada por el número de botón de verificación dentro delrange(10)
.Supongamos además que desea escribir un controlador llamado
.__cbHandler
para los.__cbHandler
en los diez de estos botones de verificación. El controlador puede obtener el widget
Checkbutton
real que lo activó refiriéndose al atributo.widget
del objeto deEvent
que se pasa, pero ¿cómo encuentra el índice de dicho botón enself.cbList
?Sería bueno escribir nuestro controlador con un argumento adicional para el número de botón de verificación, algo como esto:
def __cbHandler ( self, event, cbNumber ):
Pero los controladores de eventos solo pasan un argumento, el evento. Por lo tanto, no podemos usar la función anterior debido a una falta de coincidencia en el número de argumentos.
Afortunadamente, la capacidad de Python para proporcionar valores predeterminados para los argumentos de la función nos da una salida. Echa un vistazo a este código:
def __createWidgets ( self ): ? self.cbList = [] # Create the checkbutton list for i in range(10): cb = Checkbutton ( self, ? ) self.cbList.append ( cb ) cb.grid( row=1, column=i ) def handler ( event, self=self, i=i ): # [1] return self.__cbHandler ( event, i ) cb.bind ( "
", handler ) ? def __cbHandler ( self, event, cbNumber ): ?
#
[1] Estas líneas definen un nuevohandler
funciones que espera tres argumentos. El primer argumento es el objeto deEvent
que se pasa a todos los controladores de eventos, y el segundo y tercer argumentos se establecerán en sus valores predeterminados: los argumentos adicionales que necesitamos para pasarlo.Esta técnica se puede ampliar para proporcionar cualquier número de argumentos adicionales a los manejadores.
Una forma ligeramente más concisa de hacer esto, como lo hace Bryan Oakley para el segundo botón en su respuesta , es definir cada función de controlador en línea con una lambda, es decir:
def __createWidgets ( self ): ? self.cbList = [] # Create the checkbutton list for i in range(10): cb = Checkbutton ( self, ? ) self.cbList.append ( cb ) cb.grid( row=1, column=i ) cb.bind ( "", lambda event, self=self, i=i: self.__cbHandler( event, i ) ) ? def __cbHandler ( self, event, cbNumber ): ?