Interfaces gráficas de usuario
Una interfaz gráfica invierte el control: el programa ya no manda, espera. Ese cambio de mentalidad —del programa secuencial al bucle de eventos— es lo que hay que entender primero.
01El programa deja de mandar
Un programa de consola manda: pide un dato, calcula, imprime, termina. Una interfaz gráfica invierte esa relación. El programa arranca, dibuja la ventana y se queda esperando; quien decide qué pasa es el usuario.
| Programa secuencial | Programa orientado a eventos |
|---|---|
| El código controla el orden | El usuario controla el orden |
scanf bloquea hasta que haya dato | Nadie bloquea: se avisa cuando hay algo |
| Empieza y termina | Vive en un bucle hasta que se cierra la ventana |
| Una sola línea de ejecución | Muchos manejadores, cada uno cortito |
Debajo de toda interfaz gráfica hay el mismo bucle, tenga el nombre que tenga:
mientras la ventana esté abierta:
evento = sacar_de_la_cola() # espera si no hay
manejador = buscar_quien_lo_atiende(evento)
manejador(evento)
redibujar_lo_que_cambió()
El sistema operativo va depositando en esa cola cada clic, cada tecla y cada movimiento del mouse. El programa los saca de a uno y llama al manejador que corresponda.
Usá los controles de abajo: cada acción encola un evento. Procesalos de a uno y mirá qué manejador se ejecuta.
02Widgets y contenedores
Una interfaz se arma con widgets —los controles— metidos dentro de contenedores que deciden cómo se acomodan. El árbol de contenedores es lo que hace que la ventana se adapte al redimensionarse, en lugar de quedar con todo en coordenadas fijas.
| Widget | Para qué | Evento que genera |
|---|---|---|
| Botón | Disparar una acción | clic |
| Campo de texto | Escribir un valor | cambio, tecla, foco |
| Casilla y opción | Elegir entre alternativas | cambio de estado |
| Deslizador | Un valor continuo | cambio, muchas veces por segundo |
| Lista y tabla | Mostrar y elegir registros | selección |
| Lienzo | Dibujar libremente | redibujado, mouse |
Para acomodarlos hay dos criterios: posiciones absolutas —rápido de hacer, se rompe en cuanto cambia el tamaño o el tipo de letra— y gestores de disposición por filas, columnas o grilla, que es lo que conviene siempre.
03Separar la interfaz de la lógica
La regla que más problemas evita: el manejador de un botón no hace el trabajo, sólo llama a quien lo hace. Si el cálculo, la medición o el acceso al equipo están escritos dentro del manejador, no se pueden probar sin abrir la ventana, ni reutilizar desde un script.
def al_pulsar_medir(): # manejador: tres líneas
v = instrumento.medir_tension() # la lógica, aparte
etiqueta.config(text=f"{v:.3f} V")
grafico.agregar(v)
Ese es el fondo de los patrones que se estudian con nombre propio —modelo-vista-controlador y sus variantes—: el modelo tiene los datos y las reglas, la vista los muestra y el controlador traduce los eventos en llamadas al modelo.
Si un manejador tarda dos segundos, la ventana queda congelada dos segundos: no redibuja, no responde y el sistema la marca como «no responde». Todo lo que demore —leer un puerto, descargar, calcular mucho— va en otro hilo, y cuando termina avisa a la interfaz. La regla es estricta: sólo el hilo de la interfaz puede tocar los widgets; los demás le mandan el resultado con una cola o con el mecanismo que provea la biblioteca.
04Una interfaz de instrumentación
En electrónica, la interfaz casi siempre acompaña a un equipo: un banco de medición, un control de proceso, un registrador. Lo que se espera de ella:
- Estado visible. Conectado o no, en qué puerto, desde cuándo.
- Lectura continua sin trabar. Un hilo lee el instrumento; la interfaz se refresca cada 100 o 200 ms, no a 60 cuadros por segundo.
- Unidades y cifras significativas. Mostrar 3,7 V, no 3,700000001.
- Registro y exportación. Guardar la serie en CSV es lo primero que va a pedir quien la use.
- Errores a la vista. Si se desconectó el equipo, decirlo, no dejar el último valor congelado.
- Confirmación de lo peligroso. Una salida de potencia no se enciende con un clic distraído.
| Entorno | Lenguaje | Dónde encaja |
|---|---|---|
| Tkinter | Python | Viene con Python; ideal para empezar y para herramientas internas |
| Qt (PyQt / Qt en C++) | Python o C++ | Aplicaciones grandes, multiplataforma, con gráficos |
| Dear ImGui | C++ | Paneles de depuración y herramientas de laboratorio |
| Interfaz web local | Cualquiera + navegador | El equipo sirve una página; se usa desde cualquier máquina |
05En el laboratorio
Armar una ventana con un botón, un campo y un deslizador, y hacer que cada manejador imprima en consola qué evento llegó. Mover el deslizador y contar cuántos eventos genera un solo arrastre.
Poner un sleep(3) dentro del manejador de un botón y comprobar que la interfaz queda
muerta. Después mover ese trabajo a un hilo y verificar que la ventana sigue viva.
Con el protocolo de la página anterior, hacer una interfaz que encienda y apague una salida, fije un PWM con un deslizador y muestre la lectura del sensor en un gráfico que avanza.
06Errores frecuentes
- Hacer el trabajo pesado en el manejador y congelar la ventana.
- Tocar widgets desde otro hilo. Es la causa de los cuelgues más difíciles de reproducir.
- Mezclar la lógica con la interfaz y quedarse sin manera de probar nada.
- Posicionar todo en coordenadas absolutas y que se rompa al cambiar el tamaño.
- Redibujar el gráfico entero a 60 cuadros por segundo cuando el dato cambia diez veces por segundo.
- No informar el error y dejar el último valor en pantalla como si fuera actual.
07Autoevaluación
¿Qué es el bucle de eventos?
El ciclo que saca eventos de la cola, llama al manejador que corresponde y redibuja. Toda interfaz gráfica tiene uno.
¿Por qué se congela una ventana?
Porque un manejador está tardando y el bucle no puede seguir procesando eventos ni redibujando.
¿Puede un hilo de trabajo actualizar una etiqueta directamente?
No: sólo el hilo de la interfaz puede tocar los widgets. El hilo de trabajo le manda el resultado por una cola o por el mecanismo que dé la biblioteca.
¿Cuántos eventos genera arrastrar un deslizador?
Muchos, uno por cada cambio de valor. Por eso el manejador de un deslizador tiene que ser barato, o hay que espaciar el trabajo real.
¿Qué ventaja tiene un gestor de disposición sobre las coordenadas fijas?
Que la ventana se adapta al cambiar de tamaño, de resolución o de tipo de letra sin que se superpongan los controles.
¿Qué separa el patrón modelo-vista-controlador?
Los datos y las reglas (modelo), lo que se muestra (vista) y la traducción de eventos en acciones (controlador). Permite probar la lógica sin abrir la ventana.
08Para ampliar
- Mark Summerfield. Rapid GUI Programming with Python and Qt. Prentice Hall, 2007. Eventos, hilos y diseño de interfaces con criterio de aplicación real.
- Documentación oficial de Python. tkinter — Interface to Tcl/Tk. Python Software Foundation. La biblioteca que ya viene instalada: suficiente para la mayoría de las herramientas de laboratorio.
- Jakob Nielsen. Usability Engineering. Morgan Kaufmann, 1993. Las heurísticas clásicas: visibilidad del estado, prevención de errores, control del usuario.