Ir al contenido

IDEAS PRÁCTICAS · ASIMOV INGENIERÍA

6 Eventos en Tkinter: del clic del mouse a tus funciones Python

Aprende a manejar eventos en Tkinter, diferencia entre `command=` y `bind()`, y descubre ejemplos prácticos de mouse y teclado con acceso a la información del evento.

Imagen ilustrativa · Brecht Corbeel / Unsplash.

Table of contents

No titles in the blog post

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.

Computadora portátil encendida en un escritorio
Imagen ilustrativa · AltumCode / Unsplash.

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, Canvas o 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

EventoDescripció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

EventoDescripció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 Label mediante command= (sin información del evento).
  • Al hacer clic dentro del Canvas, el Label muestra 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 bind se ejecutan en el hilo principal de la GUI; evita operaciones costosas (I/O, cálculos intensivos). Usa threading o after() para delegar trabajo.
  • Para eventos que se disparan con alta frecuencia (<Motion>), considera event.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

Aspectocommand=bind()
Tipo de widgetSolo widgets con soporte (Button, Menu, etc.)Cualquier widget
Argumentos del callbackSin argumentosRecibe Event
Acceso a coordenadas/teclasNo disponibleDisponible
Flexibilidad de eventosSolo "activación" predeterminadaTodos los eventos (click, doble click, teclado, foco, etc.)
Uso típicoAcciones 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.