DMarlon Studio

Lección 5 · 5 de 20

Treeview como árbol · tkinter

Construya un árbol de carpetas con ttk.Treeview de tkinter: nodos padre e hijo, ramas abiertas o cerradas y una función recursiva.

tkinter · Treeview como árbol en DMarlon Studio: el código del ejemplo y la ventana que abre al ejecutarlo

El mismo ttk.Treeview muestra jerarquías. Aquí no se oculta la columna #0: es la del árbol, con las flechas para abrir y cerrar ramas. heading("#0", ...) le pone título, y size es una columna más, a la derecha.

Los datos son diccionarios dentro de diccionarios: una carpeta es un diccionario y un archivo, su tamaño. La función add los recorre y se llama a sí misma con cada carpeta (es recursiva), así que sirve para cualquier profundidad.

La clave está en el primer argumento de insert: el padre. Con "", el nodo cuelga de la raíz; con el identificador de otro nodo, se convierte en su hijo. Cada nodo usa su ruta (project/src/app.py) como iid, así que es único y fácil de buscar. open=True deja la carpeta abierta; aquí, todas salvo photos.

text es lo que se ve en la columna del árbol y values, el resto de columnas (las carpetas no llevan tamaño). Al elegir un nodo, la etiqueta enseña su ruta y la de su padre, que da parent(). También existen get_children(iid) para los hijos e item(iid, open=False) para cerrar una rama.

En DMarlon Studio, la Tabla de datos de la paleta es este mismo ttk.Treeview, preparado como tabla; los árboles se rellenan desde el código con insert(padre, ...), como aquí.

Código · main.py

import tkinter as tkfrom tkinter import ttkfiles = {"project": {"src": {"main.py": "4 KB", "app.py": "12 KB"}, "README.md": "2 KB",                     "docs": {"manual.pdf": "1.2 MB", "notes.txt": "3 KB"}},         "photos": {"2025": {"beach.jpg": "3.1 MB"}, "cat.png": "640 KB"}}root = tk.Tk()root.title("Files")root.geometry("460x310")# Column #0 is the tree itself; "size" is an extra column.tree = ttk.Treeview(root, columns=("size",))tree.heading("#0", text="Name", anchor="w")tree.heading("size", text="Size", anchor="e")tree.column("size", width=100, anchor="e")def add(parent, items):  # insert(parent, ...) makes a child of that node    for name, value in items.items():        path = f"{parent}/{name}" if parent else name        folder = isinstance(value, dict)  # open=True shows a folder's children        tree.insert(parent, "end", iid=path, text=name + "/" * folder,                    values=() if folder else (value,), open=name != "photos")        if folder:            add(path, value)add("", files)info = ttk.Label(root)info.pack(side="bottom", anchor="w", padx=12, pady=(0, 10))tree.pack(fill="both", expand=True, padx=10, pady=10)tree.bind("<<TreeviewSelect>>", lambda e: info.config(    text=f"Selected: {tree.focus()}   (parent: {tree.parent(tree.focus())})"))tree.selection_set("project/src/app.py")tree.focus("project/src/app.py")root.mainloop()

Para recordar

  • La columna #0 es el árbol; las demás son values.
  • El primer argumento de insert es el padre.
  • open=True deja una rama abierta.
  • Una función recursiva recorre cualquier profundidad.

Ejercicio

Añada la carpeta project/tests con dos archivos, haga que empiece cerrada y que, al abrirse la ventana, esté elegido README.md.