Eventos en Tkinter: del clic del mouse a tus funciones Python
Tkinter es la biblioteca estándar de Python para crear interfaces gráficas. Más allá de los widgets estáticos, la verdadera interactividad surge gracias a los eventos. En este artículo desglosamos cuándo usar command= y cuándo recurrir a bind(), mostramos los eventos de ratón y teclado más habituales, y ofrecemos ejemplos listos para copiar.
1. El loop de eventos de Tkinter
Tkinter funciona sobre un event loop que espera a que el usuario realice alguna acción (clic, pulsación de tecla, movimiento del ratón, etc.). Cada acción genera un evento que el motor de Tkinter entrega a los widgets que se hayan suscrito a él.
El objeto Event que llega a la función manejadora contiene atributos útiles como x, y (coordenadas relativas al widget), widget (referencia al widget origen), char (carácter pulsado) y keysym (nombre de la tecla).
2. command= vs bind()
Uso de command=
- Se asocia exclusivamente a widgets que lo soportan (Button, Checkbutton, Radiobutton, Menubutton, etc.).
- El callback se ejecuta **solo** cuando el widget se activa de forma predeterminada (p.ej., al soltar el botón del ratón sobre un
Button). - No recibe ningún argumento; la función debe estar preparada para ejecutarse sin parámetros.
- Ideal para acciones simples y de alto nivel ("Enviar formulario", "Abrir archivo").
Uso de bind()
- Se puede aplicar a **cualquier widget** (incluido
Frame,Canvaso la raíz). - Permite interceptar **cualquier tipo de evento**: clics, doble clics, movimientos, teclas, foco, redimensionado, etc.
- El callback recibe automáticamente el objeto
Event, lo que permite acceder a datos como coordenadas o tecla pulsada. - Mayor flexibilidad para implementar interacciones avanzadas (arrastrar‑soltar, atajos de teclado, gestos).
Regla práctica: Si el widget tiene command y solo necesitas una acción directa, úsalo. Si necesitas información del evento o un comportamiento no estándar, opta por bind().
3. Eventos de ratón más útiles
| Evento | Descripción |
|---|---|
<Button-1> | Clic izquierdo del ratón. |
<Button-2> | Clic con botón central (rueda). |
<Button-3> | Clic derecho (útil para menús contextuales). |
<Double-Button-1> | Doble clic izquierdo. |
<Triple-Button-1> | Triple clic izquierdo. |
<Motion> | Movimiento del ratón dentro del widget (se dispara continuamente). |
<Enter> | El cursor entra en el área del widget. |
<Leave> | El cursor abandona el área del widget. |
4. Eventos de teclado más usados
| Evento | Descripción |
|---|---|
<Key> | Cualquier tecla pulsada. |
<KeyPress-A> | Tecla "A" pulsada (mayúscula o minúscula según el estado de Shift). |
<KeyRelease-Return> | Se suelta la tecla Enter. |
<Return> | Enter (equivalente a KeyPress-Return). |
<Control-c> | Combinación Ctrl+C (muy útil para atajos). |
5. ¿Cómo obtener información del Event?
Cuando el callback está enlazado con bind(), Tkinter pasa automáticamente un argumento event. A continuación, los atributos más comunes:
- event.x / event.y: posición del cursor respecto al widget que generó el evento.
- event.x_root / event.y_root: coordenadas absolutas en la pantalla.
- event.widget: referencia al widget origen.
- event.char: carácter Unicode (solo para eventos de teclado).
- event.keysym: nombre simbólico de la tecla (p.ej.,
Return,Escape). - event.num: número del botón del ratón (1=izquierdo, 2=central, 3=derecho).
def mostrar_pos(event):
print(f"Coordenadas widget: ({event.x}, {event.y})")
print(f"Coordenadas pantalla: ({event.x_root}, {event.y_root})")
print(f"Widget origen: {event.widget}")
6. Mini‑ejemplo: Cambiar el texto de un Label con botón y con clic en un área
El siguiente script muestra ambas formas de interacción: un Button con command= y un Canvas que captura <Button-1>. El Label se actualiza con la información del evento.
import tkinter as tk
class DemoApp(tk.Tk):
def __init__(self):
super().__init__()
self.title("Eventos en Tkinter – Demo")
self.geometry("400x250")
self.configure(padx=20, pady=20)
# Label que mostrará los resultados
self.msg = tk.Label(self, text="Haz clic en el botón o en el área gris", font=('Helvetica', 12))
self.msg.pack(pady=10)
# Botón usando command=
btn = tk.Button(self, text="Presionar", command=self._on_button)
btn.pack(pady=5)
# Área gris (Canvas) que captura eventos de ratón
self.canvas = tk.Canvas(self, width=300, height=100, bg="#e0e0e0")
self.canvas.pack(pady=10)
self.canvas.bind("", self._on_canvas_click)
self.canvas.bind("", self._on_canvas_double)
def _on_button(self):
"""Manejador del botón (sin argumentos)."""
self.msg.config(text="Botón pulsado (command=)")
def _on_canvas_click(self, event):
"""Manejador de clic simple en el canvas.
Recibe el objeto Event con coordenadas.
"""
self.msg.config(text=f"Clic en ({event.x}, {event.y}) – botón {event.num}")
def _on_canvas_double(self, event):
"""Manejador de doble clic.
Demuestra cómo diferenciar entre un simple click y un doble click.
"""
self.msg.config(text=f"¡Doble clic en ({event.x}, {event.y})!")
if __name__ == "__main__":
app = DemoApp()
app.mainloop()
Ejecuta el script y observa:
- El botón actualiza el
Labelmediantecommand=(sin información del evento). - Al hacer clic dentro del
Canvas, elLabelmuestra las coordenadas exactas y el número del botón. - Un doble clic produce un mensaje distinto, demostrando cómo
bind()permite manejar varios tipos de interacción.
7. Buenas prácticas, depuración y rendimiento
7.1. Evita mezclar command y bind en el mismo widget
Si un Button tiene tanto command como un bind(<Button-1>), el orden de ejecución depende de la versión de Tk. Lo más seguro es elegir una única estrategia para evitar comportamientos inesperados.
7.2. Desvincular eventos (unbinding)
# Guardar el identificador del binding
bind_id = widget.bind("", callback)
# Más tarde, eliminarlo
widget.unbind("", bind_id)
Útil cuando necesitas habilitar/deshabilitar temporalmente la interacción.
7.3. Uso de event.widget para callbacks genéricos
Si deseas un mismo manejador para varios widgets, aprovecha event.widget para identificar el origen:
def generico(event):
widget = event.widget
widget.configure(bg='lightgreen')
7.4. Depuración de eventos
Durante el desarrollo, imprimir el objeto event ayuda a descubrir qué atributos están disponibles:
def debug(event):
print(event.__dict__)
7.5. Rendimiento
- Los callbacks de
bindse ejecutan en el hilo principal de la GUI; evita operaciones costosas (I/O, cálculos intensivos). Usathreadingoafter()para delegar trabajo. - Para eventos que se disparan con alta frecuencia (
<Motion>), consideraevent.widget.after_idle()para limitar la frecuencia de actualización.
7.6. Compatibilidad y versiones
Los nombres de eventos son estables desde Tk 8.5 (Python 3.4). Sin embargo, algunos eventos específicos de plataformas (por ejemplo, <MouseWheel> en Windows vs <Button-4/5> en X11) requieren detección de sys.platform para una experiencia multiplataforma.
8. Resumen rápido
| Aspecto | command= | bind() |
|---|---|---|
| Tipo de widget | Solo widgets con soporte (Button, Menu, etc.) | Cualquier widget |
| Argumentos del callback | Sin argumentos | Recibe Event |
| Acceso a coordenadas/teclas | No disponible | Disponible |
| Flexibilidad de eventos | Solo "activación" predeterminada | Todos los eventos (click, doble click, teclado, foco, etc.) |
| Uso típico | Acciones simples (enviar, abrir) | Interacciones avanzadas (drag‑drop, atajos, gestos) |
Dominar la diferencia entre command= y bind() te permitirá crear interfaces más intuitivas, responsivas y profesionales.
6 Eventos en Tkinter: del clic del mouse a tus funciones Python