Organizando tu GUI: Frame, Checkbutton y Radiobutton
¿Qué es un Frame?
Un Frame es simplemente un contenedor que agrupa widgets dentro de una ventana Tk. Sirve para:
- Dividir la interfaz en áreas lógicas (p.ej. panel de opciones vs panel de resultados).
- Aplicar estilos o layout managers diferentes en cada zona.
- Facilitar el mantenimiento y la reutilización de código.
En términos de Bootstrap, equivale a una .card o a una columna de la cuadrícula.
Variables de control
Tkinter usa objetos especiales para almacenar el estado de los widgets interactivos. Los más comunes son:
IntVar: almacena valores enteros (0/1 paraCheckbutton, índices paraRadiobutton).BooleanVar: similar aIntVarpero semánticamente representaTrue/False.StringVar: guarda texto, útil cuando el valor delRadiobuttones una cadena.
Estas variables permiten que varios widgets compartan el mismo estado y que el programa lea o modifique dicho estado de forma reactiva.
Checkbutton
Un Checkbutton representa una opción binaria (activada/desactivada). Se enlaza a una variable (IntVar o BooleanVar) mediante el argumento variable=.
Ejemplo de uso típico:
show_title = BooleanVar(value=True)
Checkbutton(frame, text="Mostrar título", variable=show_title)
Radiobutton
Los Radiobutton forman un grupo de opciones mutuamente excluyentes. Todos comparten la misma variable; cada botón define su propio value.
Ejemplo con StringVar:
color = StringVar(value="rojo")
Radiobutton(frame, text="Rojo", variable=color, value="rojo")
Radiobutton(frame, text="Verde", variable=color, value="verde")
Ejemplo práctico
El siguiente script muestra cómo combinar Frame, Checkbutton y Radiobutton. El usuario selecciona varias opciones y, al pulsar Actualizar, el Label muestra el estado actual.
import tkinter as tk
from tkinter import ttk
# ------------------------------------------------------------------
# 1️⃣ Configuración de la ventana principal
# ------------------------------------------------------------------
root = tk.Tk()
root.title("Demo: Frame + Checkbutton + Radiobutton")
root.geometry("500x300")
# ------------------------------------------------------------------
# 2️⃣ Variables de control
# ------------------------------------------------------------------
show_name = tk.BooleanVar(value=True) # Checkbutton
show_email = tk.BooleanVar(value=False) # Checkbutton
theme_color = tk.StringVar(value="azul") # Radiobutton
# ------------------------------------------------------------------
# 3️⃣ Frame contenedor de los controles
# ------------------------------------------------------------------
control_frame = ttk.LabelFrame(root, text="Opciones")
control_frame.pack(fill="both", expand=True, padx=15, pady=15)
# Checkbuttons ------------------------------------------------------
ck_name = ttk.Checkbutton(control_frame, text="Mostrar nombre", variable=show_name)
ck_email = ttk.Checkbutton(control_frame, text="Mostrar email", variable=show_email)
ck_name.grid(row=0, column=0, sticky="w", padx=5, pady=5)
ck_email.grid(row=1, column=0, sticky="w", padx=5, pady=5)
# Radiobuttons ------------------------------------------------------
colors = ["azul", "verde", "rojo"]
for idx, col in enumerate(colors):
rb = ttk.Radiobutton(
control_frame,
text=col.capitalize(),
variable=theme_color,
value=col
)
rb.grid(row=0, column=idx+1, padx=5, pady=5)
# ------------------------------------------------------------------
# 4️⃣ Área de salida (Label) y botón de actualización
# ------------------------------------------------------------------
output_label = ttk.Label(root, text="", anchor="center", font=("Helvetica", 12))
output_label.pack(fill="x", padx=15, pady=10)
def actualizar():
"""Construye una cadena con el estado actual y la muestra en el label."""
partes = []
if show_name.get():
partes.append("Nombre")
if show_email.get():
partes.append("Email")
# Siempre mostramos el color seleccionado
partes.append(f"Tema: {theme_color.get().capitalize()}")
output_label.config(text=", ".join(partes))
btn_update = ttk.Button(root, text="Actualizar", command=actualizar)
btn_update.pack(pady=5)
# Iniciamos la GUI
root.mainloop()
Explicación de los puntos clave:
LabelFrameactúa comoFramecon título.- Las variables se crean antes de los widgets para que puedan ser compartidas.
- Se usa
griddentro del frame para alinear los controles. - La función
actualizarlee los valores deBooleanVaryStringVary actualiza elLabel.
Buenas prácticas y solución de problemas
- Separar lógica y presentación: mantén la creación de widgets en una función o clase y la lógica de negocio en otra.
- Inicializar variables con valor por defecto: evita estados None inesperados.
- Usar
ttken lugar de los widgets clásicos: ofrecen una apariencia nativa y son más fáciles de tematizar. - Depuración: imprime el valor de las variables con
print(var.get())dentro de la callback para validar su contenido. - Accesibilidad: asigna
focus()al primer control y usaAlt+Keyen el texto del botón para usuarios de teclado.