Diálogos y ventanas emergentes en Tkinter: messagebox y filedialog
Tkinter incluye un conjunto de utilidades que facilitan la interacción con el usuario: messagebox para mostrar mensajes y filedialog para abrir o guardar archivos. En este artículo veremos su sintaxis, ejemplos listos para copiar‑pegar, buenas prácticas de seguridad y rendimiento, y cómo resolver los problemas más habituales.
MessageBox: tipos y ejemplos
El módulo tkinter.messagebox ofrece funciones estáticas que crean diálogos modales. Cada función devuelve un valor que permite tomar decisiones en tiempo de ejecución.
Tipos más usados
- showinfo: información general.
- showwarning: advertencia.
- showerror: error crítico.
- askquestion: Sí/No (devuelve
'yes'o'no'). - askyesno: devuelve
True/False. - askokcancel: devuelve
True/False.
Ejemplo completo
import tkinter as tk
from tkinter import messagebox
def demo_messagebox():
root = tk.Tk()
root.withdraw() # Ocultamos la ventana principal
# 1. Información
messagebox.showinfo('Información', 'Operación completada con éxito.')
# 2. Advertencia
messagebox.showwarning('Advertencia', 'El archivo ya existe y será sobrescrito.')
# 3. Error
messagebox.showerror('Error', 'No se pudo conectar al servidor.')
# 4. Pregunta Sí/No
respuesta = messagebox.askyesno('Confirmar', '¿Deseas continuar?')
if respuesta:
print('El usuario aceptó')
else:
print('El usuario canceló')
root.destroy()
if __name__ == '__main__':
demo_messagebox()
En aplicaciones reales, es buena práctica destruir la ventana raíz después de usar los diálogos para evitar procesos zombie.
FileDialog: abrir y guardar archivos
El módulo tkinter.filedialog proporciona diálogos nativos del sistema operativo, lo que garantiza consistencia visual y seguridad de ruta.
Funciones principales
- askopenfilename: devuelve la ruta del archivo seleccionado para lectura.
- asksaveasfilename: devuelve la ruta donde se guardará el archivo.
- askopenfilenames: permite seleccionar múltiples archivos.
- askdirectory: devuelve la ruta de una carpeta.
Ejemplo de apertura y guardado
import tkinter as tk
from tkinter import filedialog, messagebox
def abrir_archivo():
ruta = filedialog.askopenfilename(
title='Selecciona un archivo de texto',
filetypes=[('Texto plano', '*.txt'), ('Todos los archivos', '*.*')]
)
if not ruta:
return None
try:
with open(ruta, 'r', encoding='utf-8') as f:
contenido = f.read()
return contenido
except Exception as e:
messagebox.showerror('Error de lectura', str(e))
return None
def guardar_archivo(texto):
ruta = filedialog.asksaveasfilename(
title='Guardar como',
defaultextension='.txt',
filetypes=[('Texto plano', '*.txt')]
)
if not ruta:
return False
try:
# Seguridad: crear directorio si no existe
import os
os.makedirs(os.path.dirname(ruta), exist_ok=True)
with open(ruta, 'w', encoding='utf-8') as f:
f.write(texto)
messagebox.showinfo('Guardado', f'Archivo guardado en {ruta}')
return True
except Exception as e:
messagebox.showerror('Error de escritura', str(e))
return False
Ejemplo completo: abrir un archivo de texto y mostrarlo en Text
Este mini‑editor muestra en tiempo real el contenido del archivo y permite guardarlo con el mismo formato.
import tkinter as tk
from tkinter import filedialog, messagebox, scrolledtext
class TextEditor:
def __init__(self, master):
self.master = master
master.title('Editor sencillo con Tkinter')
master.geometry('800x600')
# Barra de herramientas
toolbar = tk.Frame(master, bd=1, relief=tk.RAISED)
btn_abrir = tk.Button(toolbar, text='Abrir', command=self.abrir)
btn_guardar = tk.Button(toolbar, text='Guardar', command=self.guardar)
btn_abrir.pack(side=tk.LEFT, padx=2, pady=2)
btn_guardar.pack(side=tk.LEFT, padx=2, pady=2)
toolbar.pack(side=tk.TOP, fill=tk.X)
# Widget Text con scroll automático
self.text = scrolledtext.ScrolledText(master, wrap=tk.WORD, undo=True)
self.text.pack(expand=1, fill='both')
def abrir(self):
ruta = filedialog.askopenfilename(
title='Abrir archivo',
filetypes=[('Texto plano', '*.txt'), ('Todos los archivos', '*.*')]
)
if ruta:
try:
with open(ruta, 'r', encoding='utf-8') as f:
contenido = f.read()
self.text.delete('1.0', tk.END)
self.text.insert(tk.END, contenido)
self.master.title(f'Editor - {ruta}')
except Exception as e:
messagebox.showerror('Error', f'No se pudo leer el archivo:\n{e}')
def guardar(self):
ruta = filedialog.asksaveasfilename(
title='Guardar archivo',
defaultextension='.txt',
filetypes=[('Texto plano', '*.txt')]
)
if ruta:
try:
contenido = self.text.get('1.0', tk.END)
with open(ruta, 'w', encoding='utf-8') as f:
f.write(contenido)
messagebox.showinfo('Guardado', f'Archivo guardado en {ruta}')
self.master.title(f'Editor - {ruta}')
except Exception as e:
messagebox.showerror('Error', f'No se pudo guardar el archivo:\n{e}')
if __name__ == '__main__':
root = tk.Tk()
app = TextEditor(root)
root.mainloop()
Aspectos a considerar:
- Usar
encoding='utf-8'evita errores con caracteres internacionales. - El widget
ScrolledTextincluye barra de desplazamiento automática y es ideal para textos largos. - Desactivar la opción
master.withdraw()permite que la ventana principal sea visible mientras se usan diálogos.
Problemas comunes y cómo resolverlos
1. Diálogos que no aparecen o aparecen detrás de la ventana principal
Esto ocurre cuando la ventana raíz está minimizada o no tiene foco. Solución:
- Antes de llamar a
messageboxofiledialog, ejecutarroot.lift()yroot.focus_force(). - Si trabajas con múltiples ventanas, pasa el argumento
parent=ventana_actualal dialogo.
2. Error UnicodeDecodeError al abrir archivos
Los archivos pueden estar codificados en ANSI, UTF‑16 o UTF‑8 con BOM. Recomendaciones:
- Utiliza
open(ruta, 'r', encoding='utf-8', errors='replace')para sustituir caracteres no válidos. - Detecta la codificación con la librería
chardetantes de leer.
3. Diálogo de guardado que sobrescribe archivos sin advertencia
Para evitar pérdida de datos:
- Usa
messagebox.askyesnopara confirmar sobrescritura. - Comprueba si el archivo existe con
os.path.exists(ruta)antes de escribir.
4. Problemas de compatibilidad en macOS/Linux (diálogos sin estilo nativo)
En Linux, asegúrate de instalar tkinter del paquete python3-tk. En macOS, la versión de Python incluida en el sistema ya incluye Tk 8.6, pero si usas brew, instala brew install python-tk.
5. Rendimiento al cargar archivos muy grandes (>10 MB)
Los diálogos son sincrónicos y bloquearán la UI mientras se leen los datos. Solución:
- Lee el archivo en un hilo separado (
threading.Thread) y actualiza el widget conafter(). - Si solo necesitas una vista previa, lee los primeros
nkilobytes y muestra "…" al final.
10 Diálogos y ventanas emergentes en Tkinter: messagebox y filedialog