¿Obteniendo el widget que desencadenó un evento?

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 del range(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 de Event que se pasa, pero ¿cómo encuentra el índice de dicho botón en self.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 nuevo handler funciones que espera tres argumentos. El primer argumento es el objeto de Event 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 ): ?