Lista (Listbox) en Tcl/Tk (tkinter)



La lista (Listbox) es un control de la interfaz de usuario de Tcl/Tk que permite presentar una secuencia de cadenas de caracteres.

Lista en Tcl/Tk (tkinter)

Este widget no permite añadir íconos ni columnas. Para ello, utilícese la vista de árbol (Treeview).

Para añadir una lista a una ventana de Tk, creamos una instancia de la clase tkinter.Listbox.

#!/usr/bin/env python
# -*- coding: utf-8 -*-

import tkinter as tk
from tkinter import ttk

class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Lista en Tcl/Tk")
        
        self.listbox = tk.Listbox(self)
        self.listbox.pack()
        self.pack()

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

Manejando los elementos

Podemos añadir un ítem a la lista vía la función insert (ubicar el siguiente código a continuación de la creación de la lista en la línea 14).

        self.listbox.insert(0, "Python")

El primer argumento indica la posición en la que queremos ubicar el elemento. Éste puede ser cualquier valor numérico, o bien tk.END para referirse al final de la lista.

insert() puede tomar tantos valores como elementos quieran agregarse.

        # Agregar cuatro elementos al final de la lista.
        self.listbox.insert(tk.END, "Python", "C", "C++", "Java")

Si los elementos se encuentran en una lista o tupla, también será útil:

        items = (
            "Python",
            "C",
            "C++",
            "Java"
        )
        self.listbox.insert(0, *items)

Es posible conocer la cantidad de ítems en una lista vía la función size, que devuelve un entero.

        # Imprime 4.
        print(self.listbox.size())

Para obtener un ítem de la lista conociendo su posición, utilizamos get().

        # Imprime C++.
        print(self.listbox.get(2))

Y para eliminarlo, delete().

        # Remueve el elemento C++.
        self.listbox.delete(2)

Las dos funciones anteriores también operan con rangos. Por ejemplo, el siguiente código retorna una tupla con todos los elementos de la lista.

        # Obtener ítems desde la posición 0 hasta el final.
        items = self.listbox.get(0, tk.END)

Y este otro borra todos los ítems:

        self.listbox.delete(0, tk.END)

El parámetro listvariable

Otra forma no recomendada de manejar los elementos en un Listbox es vía el sistema de variables de Tcl/Tk. Al inicializar la clase se asocia una variable, y luego todos los cambios realizados en ésta se reflejan automáticamente en la lista.

        self.items = tk.StringVar()
        self.items.set(
            "Python "
            "C "
            "C++ "
            "Java "
        )
        self.listbox = tk.Listbox(self, listvariable=self.items)

Esto probablemente resulte cómodo cuando es utilizado en Tcl, pero no está pensado para las estructuras de datos de Python. Como se puede ver, todos los ítems se añaden como una única cadena separados por un espacio. Para obtener los elementos de la lista, la función get() también retorna una cadena.

        items = self.items.get()
        print(items, type(items))

Esto imprime:

('Python', 'C', 'C++', 'Java') <class 'str'>

Si quisiéramos acceder a un elemento en particular, deberíamos convertirlo a una tupla real vía la función más insegura en todo el lenguaje: eval().

        # Convertir a una tupla.
        t = eval(self.items.get())
        # Acceder al primer elemento.
        print(t[0])

Obtener y establecer la selección

Por defecto una lista solo puede tener un ítem seleccionado (tk.BROWSE). Para cambiar este comportamiento y permitir múltiples selecciones, debe pasarse el valor tk.EXTENDED al parámetro selectmode.

        # Permitir múltiples selecciones.
        self.listbox = tk.Listbox(self, selectmode=tk.EXTENDED)

La función curselection retorna una tupla con la posición de los elementos seleccionados.

self.listbox.curselection()

Para añadir uno o varios elementos a la selección utilizamos selection_set.

        # Seleccionar el tercer elemento.
        self.listbox.selection_set(2)
        # Seleccionar todos los elementos.
        self.listbox.selection_set(0, tk.END)

De forma similar opera selection_clear(), para remover la selección.

Por último, selection_includes() retorna True si el ítem con la posición indicada se encuentra seleccionado; False en caso contrario.

        self.listbox.selection_set(2)
        # Imprime True.
        print(self.listbox.selection_includes(2))

Estilos

La clase Listbox acepta una serie de parámetros para modificar el estilo de la lista.

Notarás que, por defecto, el widget contiene un borde. La propiedad que controla este estilo es borderwidth, que indica su tamaño en píxeles. Para removerlo utilícese:

        self.listbox = tk.Listbox(self, borderwidth=0)

Además, los elementos tendrán un subrayado cuando estén seleccionados. Para removerlo debe configurarse la propiedad activestyle a tk.NONE (otro valor puede ser tk.DOTBOX, para dibujar un recuadro de puntos).

        self.listbox = tk.Listbox(self, activestyle=tk.NONE)

Tk permite configurar el color del borde que se muestra alrededor de la lista cuando tiene el foco. Por ejemplo, el siguiente código dibuja un recuadro de color rojo cuando el control no tiene el foco y uno de color azul cuando sí lo tiene.

        self.listbox = tk.Listbox(self, highlightcolor="#0000ff",
                                  highlightbackground="#ff0000")

También es posible indicar el grosor, en píxeles, vía highlightthickness.

El fondo y el color del texto de la lista en general es controlado por las propiedades background o bg y foreground o fg, respectivamente.

        # Fondo negro y texto blanco.
        self.listbox = tk.Listbox(self, bg="#000", fg="#fff")

Lista con fondo negro y texto blanco en Tcl/Tk (tkinter)

Otras propiedades configurables incluyen selectbackground, selectforeground y selectborderwidth, que determinan el color de fondo, color de texto y tamaño del borde de un elemento seleccionado.

        # Fondo verde con texto blanco para la selección.
        self.listbox = tk.Listbox(self, selectforeground="#ffffff",
                                  selectbackground="#00aa00",
                                  selectborderwidth=5)

Elemento seleccionado con fondo verde y texto blanco en Tcl/Tk (tkinter)

Y para indicar la fuente:

        self.listbox = tk.Listbox(self,
            font=Font(family="Sans Serif", size=10))

(Debe importarse Font previamente vía from tkinter.font import Font).

Por último, también puede darse estilo a elementos individuales, indicando su posición vía la función itemconfigure.

        self.listbox = tk.Listbox(self)
        self.listbox.insert(0, "Python", "C", "C++", "Java")
        self.listbox.itemconfigure(0, bg="#00aa00", fg="#fff")
        self.listbox.itemconfigure(3, bg="#ff0000", fg="#fff")

Elementos de una lista con estilos en Tcl/Tk (tkinter)

Las propiedades válidas para elementos individuales son background o bg, foreground o fg, selectbackground y selectforeground.

Barra de deslizamiento

El siguiente código añade una barra de deslizamiento vertical (ttk.Scrollbar) cuando la cantidad de elementos de la lista excede el límite visible.

class Application(ttk.Frame):
    
    def __init__(self, main_window):
        super().__init__(main_window)
        main_window.title("Lista en Tcl/Tk")
        
        # Crear una barra de deslizamiento con orientación vertical.
        scrollbar = ttk.Scrollbar(self, orient=tk.VERTICAL)
        # Vincularla con la lista.
        self.listbox = tk.Listbox(self, yscrollcommand=scrollbar.set)
        
        # Insertar 20 elementos.
        for i in range(20):
            self.listbox.insert(tk.END, "Elemento {}".format(i))
        
        scrollbar.config(command=self.listbox.yview)
        # Ubicarla a la derecha.
        scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
        self.listbox.pack()
        
        self.pack()

Lista con barra de deslizamiento (Scrollbar) en Tcl/Tk (tkinter)

Otras funciones

La función see ajusta la visión de la lista para hacer visible un elemento determinado. Por ejemplo, en el código anterior, el Elemento 15 se encuentra fuera del rango de visión. Para deslizar la lista hacia ese ítem se utiliza:

        self.listbox.see(15)



2 comentarios.

  1. hola, buenas tardes.

    he estado ojeando el artículo. Está bien, y solo una puntualización:

    en el apartado estilos relativo al ancho del borde

    self.listbox = tk.Listbox(self, borderwidth=0)

    yo le añadiría una configuración más:

    highlightthickness=0

    para completar el engaño visual. Aunque esto tambien puede depender del widget ‘padre’

    nota: lo he probado en windows 10. Lo comento, porque en linux algunos widgets se ven distinto

    • Recursos Python says:

      Hola, ¿cómo estás? Coincido. La propiedad highlightthickness controla el grosor del borde del control cuando tiene el foco. Creí haberlo pasado por alto pero está especificado unas líneas más abajo del código al que hacés mención.

      ¡Saludos!

Deja un comentario