Ir al contenido

IDEAS PRÁCTICAS · ASIMOV INGENIERÍA

Listas desplegables y listas de selección en Tkinter: Listbox y ttk.Combobox

Aprende a usar Listbox (selección simple y múltiple) y ttk.Combobox en Tkinter, con ejemplos dinámicos de carga de datos y un ejercicio práctico para consolidar conocimientos.

Imagen ilustrativa · Rubaitul Azad / Unsplash.

Table of contents

No titles in the blog post

Listas desplegables y listas de selección en Tkinter

En este artículo exploraremos dos de los widgets más útiles para presentar opciones al usuario en aplicaciones de escritorio con Tkinter: Listbox y ttk.Combobox. Veremos su funcionamiento, casos de uso, cómo cargar datos de forma dinámica y terminaremos con un ejercicio práctico.

Computadora portátil con un editor de código
Imagen ilustrativa · Emile Perron / Unsplash.

Listbox – Selección simple y múltiple

El widget Listbox muestra una lista vertical de elementos. Cada elemento ocupa una fila y el usuario puede seleccionar una o varias filas según la configuración.

Configuración básica

import tkinter as tk

root = tk.Tk()
listbox = tk.Listbox(root, height=6, selectmode=tk.SINGLE)  # SINGLE | BROWSE | MULTIPLE | EXTENDED
listbox.pack(padx=10, pady=10)
root.mainloop()

Modos de selección:

  • tk.SINGLE: solo una fila a la vez.
  • tk.BROWSE: similar a SINGLE pero permite mover la selección con el mouse arrastrado.
  • tk.MULTIPLE: el usuario puede marcar/desmarcar filas individualmente (con Ctrl o clic).
  • tk.EXTENDED: permite rangos de selección con Shift y combinaciones con Ctrl (el más usado para selección múltiple).

Cargar datos dinámicamente

Supongamos que queremos presentar una lista de materias que proviene de una base de datos o de un archivo CSV. Podemos rellenar el Listbox con un bucle:

materias = ["Matemáticas", "Física", "Química", "Historia", "Literatura"]
for materia in materias:
    listbox.insert(tk.END, materia)

Para actualizar la lista sin recrear el widget, basta vaciarla y volver a insertar:

def actualizar_lista(nuevas_opciones):
    listbox.delete(0, tk.END)  # elimina todo
    for opt in nuevas_opciones:
        listbox.insert(tk.END, opt)

Obtener la(s) selección(es)

seleccion = [listbox.get(i) for i in listbox.curselection()]
print("Seleccionado:", seleccion)

En modo EXTENDED curselection() devuelve una tupla con los índices de todas las filas seleccionadas.

Mejores prácticas y troubleshooting

  • Scroll automático: si la lista puede crecer mucho, añada una barra de desplazamiento vinculada:
    scroll = tk.Scrollbar(root, orient=tk.VERTICAL, command=listbox.yview)
    listbox.config(yscrollcommand=scroll.set)
    scroll.pack(side=tk.RIGHT, fill=tk.Y)
  • Validación de selección: siempre compruebe que listbox.curselection() no esté vacío antes de procesar.
  • Rendimiento: para listas con miles de elementos, utilice listbox.insert en bloques o considere ttk.Treeview con vista de tabla.

ttk.Combobox – Selección de una única opción

El ttk.Combobox combina la funcionalidad de un Entry editable y una lista desplegable. Por defecto permite seleccionar **una** opción, pero también puede configurarse como read‑only para impedir la edición libre.

Creación básica

import tkinter as tk
from tkinter import ttk

root = tk.Tk()
combobox = ttk.Combobox(root, values=["Opción 1", "Opción 2", "Opción 3"], state="readonly")
combobox.current(0)  # selecciona la primera opción
combobox.pack(padx=10, pady=10)
root.mainloop()

Los parámetros clave son:

  • values: lista o tuple de opciones.
  • state: "readonly" para bloquear la edición, "normal" para permitir al usuario escribir texto libremente.

Carga dinámica de opciones (ejemplo de cursos)

Supongamos que obtenemos la lista de cursos desde una API REST o un fichero JSON. Podemos actualizar el Combobox en tiempo real:

import json

# Simulación de carga desde archivo JSON
with open('cursos.json') as f:
    datos = json.load(f)
    cursos = [c['nombre'] for c in datos['cursos']]

combobox['values'] = cursos
if cursos:
    combobox.current(0)

Para recargar bajo demanda (por ejemplo, al pulsar un botón "Actualizar"):

def refrescar():
    nuevos = obtener_cursos_desde_api()
    combobox['values'] = nuevos
    combobox.set('')  # vacía la selección actual

btn = ttk.Button(root, text="Actualizar", command=refrescar)
btn.pack(pady=5)

Obtener la opción seleccionada

seleccion = combobox.get()
print("Curso seleccionado:", seleccion)

Comparativa con Listbox

CaracterísticaListboxttk.Combobox
Selección múltipleSí (EXTENDED, MULTIPLE)No
Edición directa del valorNoSí (state="normal")
Scroll integradoNecesita Scrollbar externaAutomático al desplegar
Uso típicoListas largas, selección de varios ítemsSelección única de opciones predefinidas

Buenas prácticas y solución de problemas comunes

  • Valores vacíos: Si el Combobox se crea con values=[], la lista desplegable aparecerá vacía. Asegúrese de actualizar values antes de llamar a current().
  • Sincronización con otras UI: Cuando el valor del combobox controla la carga de otro widget (por ejemplo, una Listbox de módulos del curso), use el evento '>' para reaccionar.
    def on_curso_change(event):
        curso = combobox.get()
        modulos = cargar_modulos(curso)
        actualizar_listbox(modulos)
    
    combobox.bind('>', on_curso_change)
  • Accesibilidad: Añada tooltip o label descriptivo para lectores de pantalla.

Ejercicio final propuesto

Desarrolla una pequeña aplicación "Gestor de Inscripciones" con los requisitos siguientes:

  1. Al iniciar, carga dinámicamente una lista de carreras desde un archivo carreras.json y muéstralas en un ttk.Combobox (solo una selección).
  2. Cuando el usuario elija una carrera, carga en un Listbox los asignaturas correspondientes (puede seleccionar varias asignaturas).
  3. Incluye un botón “Inscribir” que, al pulsarse, muestra en un tkinter.messagebox la carrera elegida y la lista de asignaturas seleccionadas.
  4. Implementa validación: si no se ha seleccionado carrera o asignaturas, muestra una advertencia al usuario.
  5. Opcional: agrega una barra de progreso que simule la “carga” de datos desde una API (usa time.sleep en un hilo separado para no bloquear la UI).

Este ejercicio consolida los conceptos de:

  • Uso de ttk.Combobox y Listbox en conjunto.
  • Carga dinámica de datos y actualización de widgets.
  • Manejo de eventos y validación de entrada.
  • Buenas prácticas de arquitectura (separar lógica de carga de datos de la UI).

¡Anímate a implementarlo y comparte tu solución en los foros de la comunidad!