Tkinter - CUADROS DE DIÁLOGO Y MENSAJES


En el capítulo anterior vimos como crear una aplicación con interfaz gráfica sencilla en Tkinter. Esta aplicación consistía en un formulario que contiene un botón, y al presionar dicho botón se imprimía un texto en la consola de comandos.

Vamos a ver los cuadros de diálogo, que son unas ventanas emergentes utilizadas para notificar algo al usuario, y constituyen una salida mucho mas atractiva que la consola. Así podrás prescindir de la consola al ejecutar tu programa y tendrás la sensación de haber construido una verdadera aplicación.



Módulo tkinter.messagebox


Crea un archivo .py, escribe este código y ejecútalo:

from tkinter import *


def mostrar_mensaje():
    print('MENSAJE AL USUARIO')


root = Tk()

Button(root, text='Mostrar Mensaje', command=mostrar_mensaje).pack()

root.mainloop()

El código es sencillo:

Si ejecutas el programa verás lo siguiente:

Tkinter - Mostrar mensaje en consola

En la imágen he hecho click 5 veces sobre el botón, así que aparece el mensaje 5 veces.

Ahora vamos a redefinir la función mostrar_mensaje para que el mensaje no se muestre por la consola, sino en una ventana (cuadro de diálogo):

from tkinter import *
from tkinter.messagebox import showinfo # <--- Ojo!


def mostrar_mensaje():
    showinfo('MENSAJE', 'MENSAJE AL USUARIO') # <--- Ojo!


root = Tk()

Button(root, text='Mostrar Mensaje', command=mostrar_mensaje).pack()

root.mainloop()

Aquí hemos añadido un import: from tkinter.messagebox import showinfo

La función showinfo es la que va a mostrar el cuadro de diálogo informativo. El primer argumento es el título y el segundo el mensaje de la ventana. showinfo recibe keyword-arguments: showinfo(title='MENSAJE', message='MENSAJE AL USUARIO').

Al ejecutar el programa y hacer click sobre el botón deberías ver lo siguiente:

Tkinter - Mostrar mensaje al usuario

Fíjate en que mientras se encuentre visible el mensaje, si haces click en el botón [Mostrar Mensaje] no aparecen nuevos mensajes. Esto se debe a que showinfo bloquea el bucle root.mainloop(), que no puede continuar hasta cerrar el mensaje. En otras palabras, mientras el mensaje showinfo esté abierto el programa se encuentra en pausa.

Ahora vamos a configurar el programa cambiando el título, icono y dimensiones, y de paso vamos a ver un nuevo argumento que podemos pasar al método .pack.

El código ahora se verá así:

from tkinter import *
from tkinter.messagebox import showinfo


def mostrar_mensaje():
    showinfo('MENSAJE', 'MENSAJE AL USUARIO')


root = Tk()

# INICIO CONFIGURACIÓN ESTILO ROOT
root.title('Mi programa :)')
root.iconbitmap('globos.ico')
root.geometry('240x120')
# FIN CONFIGURACIÓN ESTILO ROOT

boton = Button(root, text='Mostrar Mensaje', command=mostrar_mensaje)

boton.pack(expand=True, fill='both')
# expand=True centra el botón
# fill='both' hace que ocupe todo el espacio disponible

root.mainloop()

He utilizado este icono: globos.ico

Si ejecutas el programa verás como el botón ocupa todo el espacio disponible del formulario. Además si redimensionas el formulario verás como el botón se adapta al nuevo tamaño. Esto es gracias al argumento fill="both" del método boton.pack. Ahora el programa se ve así:

Tkinter - FIll

Como la función mostrar_mensaje solamente ejecuta una instrucción podemos incluir esta instrucción en una función lambda y que sea esta el comando del botón. Borraríamos la función mostrar_mensaje y cambiaríamos la definición del botón:

boton = Button(root, text='Mostrar Mensaje', command=lambda:showinfo('MENSAJE', 'MENSAJE AL USUARIO'))

Tipos de tkinter.messagebox


El módulo tkinter.messagebox expone tres funciones para desplegar mensajes / cuadros de díalogo:

Las funciones showinfo, showerror y showwarning hacen exactamente lo mismo, la unica deiferencia es el logotipo del mensaje.

Vamos a crear una aplicación para ver estas tres funciones en acción:

from tkinter import Tk, Button, BOTH
from tkinter.messagebox import showinfo, showerror, showwarning


root = Tk()
root.title('Cuadros de Diálogo')
root.iconbitmap('globos.ico')
root.geometry('240x120')
root.resizable(False, False)


btnInfo = Button(root, text='showinfo', command=lambda:showinfo(
    'Ejemplo showinfo', 'Mostrando un cuadro de diálogo informativo.'
    ))

btnError = Button(root, text='showerror', command=lambda:showerror(
    'Ejemplo showerror', 'Mostrando un cuadro de diálogo de error.'
    ))

btnWarning = Button(root, text='showwarning', command=lambda:showwarning(
    'Ejemplo showwarning', 'Mostrando un cuadro de diálodo de alerta.'
    ))


btnInfo.pack(expand=True, fill=BOTH)
btnError.pack(expand=True, fill=BOTH)
btnWarning.pack(expand=True, fill=BOTH)

root.mainloop()

El programa se verá así:

Tkinter - Aplicación con tres botones

Los mensajes correspondientes a los tres botones son los siguientes:

Tkinter - showinfo, showerror y showwarning

En vista de este código y de su resultado detengámonos para revisar los siguientes puntos:



Módulo pymsgbox


El módulo pymsgbox define tres funciones que crean tres ventanas predefinidas con Tkinter:

Puedes ver estas tres funciones en acción en el siguiente ejemplo (que es una modificación del programa anterior):

from tkinter import Tk, Button, TOP, BOTH
from pymsgbox import alert, confirm, prompt


root = Tk()
root.title('Cuadros de Diálogo')
root.iconbitmap('images/globos.ico')
root.geometry('240x120')
root.resizable(False, False)


btnAlert = Button(root, text='alert', command=lambda:alert(
    title='Ejemplo alert', text='Mostrando una alerta (Observa que solo hay un botón [Aceptar])'
    ))

btnConfirm = Button(root, text='confirm', command=lambda:confirm(
    title='Ejemplo confirm', text='Mostrando un confirm (Observa que hay un botón [Aceptar] y un botón [Cancelar])'
    ))

btnPrompt = Button(root, text='prompt', command=lambda:prompt(
    title='Ejemplo prompt', text='Mostrando un prompt. Escribe lo que quieras...'
    ))


btnAlert.pack(expand=True, fill=BOTH)
btnConfirm.pack(expand=True, fill=BOTH)
btnPrompt.pack(expand=True, fill=BOTH)

root.mainloop()

Aquí tienes una ilustración que muestra las ventanas mostradas al pulsar cada uno de los botones del programa:

Módulo pymsgbox

Al cerrarse, estas ventanas devuelven un resultado que puede utilizarse para controlar el flujo del programa:

Puedes comprobar este funcionamiento en el siguiente programa:

from tkinter import Tk, Button, TOP, BOTH
from pymsgbox import alert, confirm, prompt


root = Tk()
root.title('Cuadros de Diálogo')
root.iconbitmap('images/globos.ico')
root.geometry('240x120')
root.resizable(False, False)

# INICIO DEFINICION DE FUNCIONES >>
def _confirm():
    value = confirm(title='Ejemplo confirm', text='Mostrando un confirm (Observa que hay un botón [Aceptar] y un botón [Cancelar])')

    if value == 'OK':
        print('Has pulsado el boton [Aceptar]')
    else:
        print('Has pulsado el boton [Cancelar] o [X]')

def _prompt():
    value = prompt(title='Ejemplo prompt', text='Mostrando un prompt. Escribe lo que quieras...')

    if value:
        print(f'Has introducido el texto: {value}')
    else:
        print('No has introducido un texto o has pulsado el botón [Cancel] o [X]')
# << FIN DEFINICION DE FUNCIONES

btnAlert = Button(root, text='alert', command=lambda:alert(
    title='Ejemplo alert', text='Mostrando una alerta (Observa que solo hay un botón [Aceptar])'
    ))

btnConfirm = Button(root, text='confirm', command=_confirm) # <--- Ojo!

btnPrompt = Button(root, text='prompt', command=_prompt) # <--- Ojo!


btnAlert.pack(expand=True, fill=BOTH)
btnConfirm.pack(expand=True, fill=BOTH)
btnPrompt.pack(expand=True, fill=BOTH)

root.mainloop()

Como alert siempre devuelve 'OK' no es interesante crear una función que maneje el valor devuelto, pero para confirm y prompt si resulta interesante definir funciones que hagan una cosa u otra según este valor.

Comprueba la salida por consola de este programa al pulsar los distintos botones de los cuadros de diálogo.

Tanto para pymsgbox.alert como para pymsgbox.confirm, al hacer click en el botón y mostrar el cuadro de diálogo, parece que este es bloqueante como en las funciones tkinter.messagebox. Sin embargo, si haces click varias veces en los botones de root mientras un cuadro de diálogo está abierto, una vez lo cierres verás como aparecen el resto secuencialmente (dependiendo del numero de veces que hayas pulsado los botones).

En el caso de pymsgbox.prompt no se observa un comportamiento bloqueante.



RESUMEN


En este artículo hemos visto dos módulos:

Las funciones showinfo, showerror y showwarning del módulo tkinter.messagebox, así como las funciones pymsgbox.alert y pymsgbox.confirm nos permiten desplegar un mensaje que aporte información al usuario.

Los mensajes del módulo tkinter.messagebox bloquean el bucle Tk.mainloop, es decir, mientras esté abierto un mensaje de este módulo no hay escucha de eventos.

Los cuadros de diálogo pymsgbox.alert y pymsgbox.confirm son bloqueantes, pero no detienen la escucha de eventos. Solamente retrasan la ejecución de las funciones manejadoras hasta que se cierre el cuadro de diálogo.

El módulo pymsgbox dispone además de la función pymsgbox.prompt. Esta función no es bloqueante y permite la introducción de datos por parte del usuario.

Las funciones del módulo pymsgbox, a diferencia de las del módulo tkinter.messagebox, devuelven un valor que puede utilizarse para condicionar el flujo del programa.

GG


¡Continúa aprendiendo! - Configurar Widgets en Tkinter