Lista desplegable (Combobox) en Tcl/Tk (tkinter)

Lista desplegable (Combobox) en Tcl/Tk (tkinter)

En la jerga del desarrollo de interfaces de usuario se lo conoce como Combobox, pues se trata de una combinación entre una lista y una caja de texto. Así, puede actuar como una lista desplegable con determinadas opciones y eventualmente permitir al usuario escribir un valor que no se encuentre en la lista.

Lista desplegable (ttk.Combobox) en tkinter

El control fue introducido en Tk 8.5 y es provisto a través de la clase ttk.Combobox, la cual hereda de ttk.Entry, por lo que todas las operaciones aplicables a una caja de texto también aplican para un combobox.

El siguiente código crea una simple ventana con una lista desplegable vacía.

from tkinter import ttk
import tkinter as tk

main_window = tk.Tk()
main_window.config(width=300, height=200)
main_window.title("Combobox")
combo = ttk.Combobox()
combo.place(x=50, y=50)
main_window.mainloop()

from tkinter import ttk
import tkinter as tk

class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Combobox")
        self.combo = ttk.Combobox(self)
        self.combo.place(x=50, y=50)
        main_window.config(width=300, height=200)
        self.place(width=300, height=200)

main_window = tk.Tk()
app = Application(main_window)
app.mainloop()

Para evitar que el usuario ingrese sus propios valores, es decir, para que el control se comporte únicamente como una lista desplegable y no como una caja de texto, al momento de la creación utilizamos:

combo = ttk.Combobox(state="readonly")

self.combo = ttk.Combobox(self, state="readonly")

Para añadir un conjunto de opciones, pasamos una lista al argumento values.

combo = ttk.Combobox(
    state="readonly",
    values=["Python", "C", "C++", "Java"]
)

self.combo = ttk.Combobox(
    self,
    state="readonly",
    values=["Python", "C", "C++", "Java"]
)

Un combobox en Tk trabaja únicamente con cadenas. Cualquier otro tipo de objeto será convertido antes de ser añadido a la lista.

El método Combobox.get() retorna la opción seleccionada: ya haya sido esta seleccionada a partir de una de las opciones, ya haya sido escrita manualmente por el usuario (si no se deshabilitó esta opción vía state="readonly"). Por ejemplo, el siguiente código muestra en un cuadro de diálogo la opción seleccionada en la lista desplegable tras presionar un botón.

from tkinter import messagebox, ttk
import tkinter as tk

def show_selection():
    # Obtener la opción seleccionada.
    selection = combo.get()
    messagebox.showinfo(
        message=f"La opción seleccionada es: {selection}",
        title="Selección"
    )

main_window = tk.Tk()
main_window.config(width=300, height=200)
main_window.title("Combobox")
combo = ttk.Combobox(
    state="readonly",
    values=["Python", "C", "C++", "Java"]
)
combo.place(x=50, y=50)
button = ttk.Button(text="Mostrar selección", command=show_selection)
button.place(x=50, y=100)
main_window.mainloop()

from tkinter import messagebox, ttk
import tkinter as tk


class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Combobox")
        self.combo = ttk.Combobox(
            self,
            state="readonly",
            values=["Python", "C", "C++", "Java"]
        )
        self.combo.place(x=50, y=50)
        self.button = ttk.Button(
            text="Mostrar selección",
            command=self.show_selection
        )
        self.button.place(x=50, y=100)
        main_window.config(width=300, height=200)
        self.place(width=300, height=200)

    def show_selection(self):
        # Obtener la opción seleccionada.
        selection = self.combo.get()
        messagebox.showinfo(
            message=f"La opción seleccionada es: {selection}",
            title="Selección"
        )


main_window = tk.Tk()
app = Application(main_window)
app.mainloop()

El método get() siempre retorna una cadena y, en caso de no haber ninguna selección, devuelve una cadena vacía.

También es posible obtener el índice (es decir, su posición en la lista comenzando desde el 0) del elemento seleccionado vía current().

index = combo.current()

index = self.combo.current()

Si no hay ningún elemento seleccionado o si el elemento no se encuentra entre las opciones provistas (esto es, ha sido escrito por el usuario) el valor de retorno es -1.

Análogamente, el método set() establece el contenido de la lista.

combo.set("Python")

self.combo.set("Python")

Para seleccionar un elemento según su posición o índice se utiliza asimismo el método current(), pero pasándole como argumento el elemento que debe ser seleccionado:

# Selecciona "C++".
combo.current(2)

# Selecciona "C++".
self.combo.current(2)

Para obtener todas las opciones de la lista:

# Retorna ('Python', 'C', 'C++', 'Java')
values = combo["values"]

# Retorna ('Python', 'C', 'C++', 'Java')
values = self.combo["values"]

Nótese que retorna una tupla, no una lista. Para añadir una opción sin reemplazar a las demás, utilícese:

values = list(combo["values"])
combo["values"] = values + ["Nuevo elemento"]

values = list(self.combo["values"])
self.combo["values"] = values + ["Nuevo elemento"]

Para remover todas las opciones, simplemente:

# Vaciar la lista.
combo["values"] = []

# Vaciar la lista.
self.combo["values"] = []

El control ttk.Combobox introduce un nuevo evento llamado <<ComboboxSelected>> que es enviado cuando cambia la opción seleccionada. De esta manera, es posible asociar una función a dicho evento para que sea ejecutada cada vez que el usuario cambia la opción de la lista. Por ejemplo:

from tkinter import messagebox, ttk
import tkinter as tk

def selection_changed(event):
    selection = combo.get()
    messagebox.showinfo(
        title="Nuevo elemento seleccionado",
        message=selection
    )

main_window = tk.Tk()
main_window.config(width=300, height=200)
main_window.title("Combobox")
combo = ttk.Combobox(values=["Python", "C", "C++", "Java"])
combo.bind("<<ComboboxSelected>>", selection_changed)
combo.place(x=50, y=50)
main_window.mainloop()

from tkinter import messagebox, ttk
import tkinter as tk


class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Combobox")
        self.combo = ttk.Combobox(
            self,
            values=["Python", "C", "C++", "Java"]
        )
        self.combo.bind("<<ComboboxSelected>>", self.selection_changed)
        self.combo.place(x=50, y=50)
        main_window.config(width=300, height=200)
        self.place(width=300, height=200)

    def selection_changed(self, event):
        selection = self.combo.get()
        messagebox.showinfo(
            title="Nuevo elemento seleccionado",
            message=selection
        )


main_window = tk.Tk()
app = Application(main_window)
app.mainloop()

Lista desplegable respondiendo a los eventos del usuario

Nótese que este evento no registra cambios introducidos manualmente por el usuario.

Para saber cuándo se ha abierto la lista (esto es, presionado en la flecha en el extremo derecho), en lugar de un evento simplemente se pasa una función al parámetro postcommand.

from tkinter import ttk
import tkinter as tk

def dropdown_opened():
    print("Lista desplegada.")

main_window = tk.Tk()
main_window.config(width=300, height=200)
main_window.title("Combobox")
combo = ttk.Combobox(
    values=["Python", "C", "C++", "Java"],
    postcommand=dropdown_opened
)
combo.place(x=50, y=50)
main_window.mainloop()

from tkinter import ttk
import tkinter as tk


class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Combobox")
        self.combo = ttk.Combobox(
            self,
            values=["Python", "C", "C++", "Java"],
            postcommand=self.dropdown_opened
        )
        self.combo.place(x=50, y=50)
        main_window.config(width=300, height=200)
        self.place(width=300, height=200)

    def dropdown_opened(self):
        print("Lista desplegada.")


main_window = tk.Tk()
app = Application(main_window)
app.mainloop()

Curso online 👨‍💻

¡Ya lanzamos el curso oficial de Recursos Python en Udemy! Un curso moderno para aprender Python desde cero con programación orientada a objetos, SQL y tkinter en 2024.

Consultoría 💡

Ofrecemos servicios profesionales de desarrollo y capacitación en Python a personas y empresas. Consultanos por tu proyecto.

35 comentarios.

  1. David Cabrera says:

    Y tengo otra duda más compleja creo, con TKinter se podría hacer lo siguiente:
    Cuando el user seleccione un elemento de la lista desplegable, la ventana hará un refresh automático donde las funciones se adaptarán a esa selección. Ejemplo: Calculadora de IRPF, user selecciona Aragón y las funciones y las operaciones matemáticas se adecúan al IRPF de esa CCAA.

    Gracias de antemano.

    • Recursos Python says:

      Sí se puede, utilizando el evento ComboboxSelected (como en el ejemplo) para disparar todas las actualizaciones necesarias.

      Saludos

  2. David Cabreraº says:

    Buenas, esta pregunta es de novicio pero, qué diferencia hay entre la versión normal, y la versión orientada a objetos? Gracias

    • Recursos Python says:

      Hola, David. Son formas distintas de organizar el código. Para aplicaciones grandes con interfaces complejas, conviene usar orientación a objetos para facilitar la reutilización de código. En los demás casos, la versión sin orientación a objetos está bien.

      Saludos

  3. Hola, muy buena explicación, Quería saber si existe la opción de poner un buscador en el combobox, de la lista , poder seleccionar una letra y solo aparezcan en la lista los que inician con esa letra

  4. David Martinez says:

    Hola tambien tengo una pregunta de como guardo en una tabla de base de datos sqlite3, donde tengo varias tuplas y creo dos combobox, donde en uno me da la variable y en el otro sus elementos y lo que deseo es tomar el texto de la variable y el elemento seleccionado y me lo guarde en una tabla en columnas diferentes, muchas gracias aqui dejo el codigo

    https://mypaste.dev/vYMySJep

  5. gracias por el tutorial.
    tengo una pregunta : tengo un combobox en el cual el usuario debe seleccionar una opcion con una variable str y luego tengo un .get que transforma la variable str en un entero mediante un contador guardando el valor numerico y quiero mostrar este valor en una caja de texto en mi siguiente ventana.

  6. Hola, excelente explicacion, habra alguna manera de que las opciones que despliega el combobox, vengan de un archivo de texto?

  7. como puedo generar dentro de un combobox , una muestra de diferentes elementos ( en mi caso son departamentos ) y que se abran sus datos desde la base de datos con sus caracteristicas, y que cada vez q seleccione uno en el combobox , estos se actualizen . Me esta costando asociar el combobox con la base de datos y a su vez generar una seleccion automatica de estos . Gracias!

  8. Hola gracias por el tutorial

    quisiera saber como puedo mostrar un texto en el combo que diga «Seleccione una opción» sin que este texto sea obtenido a la hora de validar

  9. Una pregunta, si quiero que en funcion de lo seleccionado en mi lista se me ejecute una funcion u otra, como debo vincularla? Llevo tiempo intentandolo y no le doy resultado. Gracias!

  10. Hola! Muy bueno el tutorial. Te hago una consulta? Yo tengo un textbox que elije una linea de colectivo. En base a la linea de colectivo que se eligió, tengo que colocar en el combobox los ramales. Tenés idea como detectar el momento en que el cursor deja de estar en el textbox (es decir, cuando se termino de escribir allí), y pasa a estar en el combobox? En ese momento deberia consultar a la bd para completar con los valores correspondientes el combobos.

    • Recursos Python says:

      Hola Sebastián, me alegro que te haya servido. Tenés que conectar el evento <FocusIn> de tu caja de texto vía el método bind() para saber cuándo recibe el foco y poder realizar la consulta. Si tenés problemas para implementar el código creá un nuevo tema en el foro.

      Saludos

  11. Muy buena información.

    Solo tengo una duda, si quiero llenar mi lista con información de mi base de datos con un select para mi
    lista desplegables que opción o función debo utilizar.

    De antemano, gracias!

  12. Buenos días!!
    Muchas gracias por este tutorial, me ha servido de gran ayuda!!! Pero una cosina, si quiero que la lista se actualice según voy escribiendo, sabes que herramienta debo usar???

    AYUDAIME PLEASEE

    Un saludo.

    • Recursos Python says:

      Hola, me alegro que te haya servido. La lista desplegable hereda la funcionalidad de la caja de texto, por lo que puedes asignarle una variable (tk.StringVar) vía el parámetro textvariable y luego determinar cuándo es modificada a través del método trace("w", callback).

      Te dejo un ejemplo aquí: https://mypaste.dev/o1eoFAXF.

      Saludos

  13. Jorge Luis Silva Ojeda says:

    Muy buena información.

    Solo tengo una duda, si quiero poner 2 listas desplegables, pero que la 2da lista dé resultados diferentes dependiendo de la opción que se dio en la 1ra, (algo así como escoger el país y que en la siguiente te dé una lista de los estados) ¿qué debería agregar?

    De antemano, gracias!

    • Recursos Python says:

      Hola. En ese caso deberías asociar el evento <<ComboboxSelected>> de la primera lista para que al seleccionar una opción se carguen los elementos de la segunda.

      Saludos

      • Cordial saludo, muchas gracias por el aporte agradezco me indiquen por favor como se puede realizar el manejo de combobox en python pero en ambiente web, Gracias!.

Deja una respuesta