69 - tkinter.messagebox : ventanas de mensajes

Las aplicaciones de escritorio es muy común la necesidad de abrir otras ventanas emergentes con el objetivo de informar, advertir de errores etc.

La librería tkinter provee un paquete llamado messagebox con una serie de funciones para la apertura de diálogos de información.

Para usar estos diálogos lo primero que debemos hacer es importar el paquete:

from tkinter import messagebox as mb

Podemos crear un alias para el nombre del paquete para no tener que escribir messagebox todas las veces.

Problema:

Confeccionar una aplicación que permita ingresar dos valores enteros y al presionar un botón nos muestre la suma en el título de la ventana. Si el operador no ingresa en alguno de los dos controles Entry datos informar mediante un diálogo el error que se está cometiendo.
Agregar además un menú de opciones que al ser seleccionado nos muestre información del programa.

La representación visual cuando se presiona el botón "sumar" y no se ingresa alguno de los dos números debe ser:

tkinter.messagebox

La representación visual cuando se abre el diálogo que informa sobre el programa desde el menú de opciones es:

tkinter.messagebox

Programa: ejercicio249.py

Ver video

import tkinter as tk
from tkinter import ttk
from tkinter import messagebox as mb

class Aplicacion:
    def __init__(self):
        self.ventana1=tk.Tk()
        self.labelframe1=ttk.LabelFrame(self.ventana1, text="Suma de números")
        self.labelframe1.grid(column=0, row=0, padx=10, pady=10)
        self.agregar_componentes()
        self.agregar_menu()
        self.ventana1.mainloop()

    def agregar_componentes(self):
        self.label1=ttk.Label(self.labelframe1, text="Ingrese primer valor:")
        self.label1.grid(column=0, row=0, padx=5, pady=5, sticky="e")
        self.dato1=tk.StringVar()
        self.entry1=ttk.Entry(self.labelframe1, textvariable=self.dato1)
        self.entry1.grid(column=1, row=0, padx=5, pady=5)
        self.label2=ttk.Label(self.labelframe1, text="Ingrese segundo valor:")
        self.label2.grid(column=0, row=1, padx=5, pady=5, sticky="e")
        self.dato2=tk.StringVar()
        self.entry2=ttk.Entry(self.labelframe1, textvariable=self.dato2)
        self.entry2.grid(column=1, row=1, padx=5, pady=5)
        self.boton1=ttk.Button(self.labelframe1, text="Sumar", command=self.sumar)
        self.boton1.grid(column=1, row=2, padx=5, pady=5, sticky="we")

    def agregar_menu(self):
        self.menubar1 = tk.Menu(self.ventana1)
        self.ventana1.config(menu=self.menubar1)
        self.opciones1 = tk.Menu(self.menubar1, tearoff=0)
        self.opciones1.add_command(label="Acerca de...", command=self.acerca)
        self.menubar1.add_cascade(label="Opciones", menu=self.opciones1)    

    def sumar(self):
        if self.dato1.get()=="" or self.dato2.get()=="":
            mb.showerror("Cuidado","No puede dejar los cuadros de entrada de números vacíos")
        else:
            suma=int(self.dato1.get())+int(self.dato2.get())
            self.ventana1.title("La suma es "+str(suma))

    def acerca(self):
        mb.showinfo("Información", "Este programa fue desarrollado para el aprendizaje de Python y tkinter.")
        
aplicacion1=Aplicacion() 

Creamos un objeto de la clase LabelFrame para disponer los controles de entrada de dato y el botón de sumar:

        self.labelframe1=ttk.LabelFrame(self.ventana1, text="Suma de números")
        self.labelframe1.grid(column=0, row=0, padx=10, pady=10)
        self.agregar_componentes()

El método agregar_componentes es donde creamos cada uno de los Widget y los agregamos al LabelFrame:

    def agregar_componentes(self):
        self.label1=ttk.Label(self.labelframe1, text="Ingrese primer valor:")
        self.label1.grid(column=0, row=0, padx=5, pady=5, sticky="e")
        self.dato1=tk.StringVar()
        self.entry1=ttk.Entry(self.labelframe1, textvariable=self.dato1)
        self.entry1.grid(column=1, row=0, padx=5, pady=5)
        self.label2=ttk.Label(self.labelframe1, text="Ingrese segundo valor:")
        self.label2.grid(column=0, row=1, padx=5, pady=5, sticky="e")
        self.dato2=tk.StringVar()
        self.entry2=ttk.Entry(self.labelframe1, textvariable=self.dato2)
        self.entry2.grid(column=1, row=1, padx=5, pady=5)
        self.boton1=ttk.Button(self.labelframe1, text="Sumar", command=self.sumar)
        self.boton1.grid(column=1, row=2, padx=5, pady=5, sticky="we")

Para no codificar el menú de opciones todo en el método __init__ procedemos a separarlo en el método agregar_menu:

    def agregar_menu(self):
        self.menubar1 = tk.Menu(self.ventana1)
        self.ventana1.config(menu=self.menubar1)
        self.opciones1 = tk.Menu(self.menubar1, tearoff=0)
        self.opciones1.add_command(label="Acerca de...", command=self.acerca)
        self.menubar1.add_cascade(label="Opciones", menu=self.opciones1)    

Cuando se presiona el botón "Sumar" se ejecuta el método 'sumar' donde verificamos mediante un if si alguno de los Entry se encuentra vacio:

    def sumar(self):
        if self.dato1.get()=="" or self.dato2.get()=="":
            mb.showerror("Cuidado","No puede dejar los cuadros de entrada de números vacíos")
        else:
            suma=int(self.dato1.get())+int(self.dato2.get())
            self.ventana1.title("La suma es "+str(suma))

Si alguno de los Entry se encuentra vacío se ejecuta el verdadero del if donde llamamos a la función 'showerror' del paquete messagebox:

            mb.showerror("Cuidado","No puede dejar los cuadros de entrada de números vacíos")

Esta función tiene dos parámetros, el primero es el mensaje del título y el segundo el cuerpo propiamente del mensaje.

Por otro lado cuando se selecciona la opción del menú "Acerca de..." se ejecuta el método acerca:

    def acerca(self):
        mb.showinfo("Información", "Este programa fue desarrollado para el aprendizaje de Python y tkinter.")

En este método llamamos a la función showinfo del paquete messagebox y le pasamos dos string para el título y el cuerpo del diálogo.

La diferencia entre los cuadros de diálogos 'showerror' y 'showinfo' es el ícono gráfico que aparece en cada uno.

Existe otra función similar en este módulo llamado 'showwarning' (dispone otro ícono en el diálogo):

tkinter.messagebox showwarning

Diálogos para confirmar o rechazar.

El paquete 'messagebox' cuenta con otra función que nos muestra un diálogo con dos botones con los mensajes "Si" o "No", luego desde nuestro programa podemos identificar cual de los dos botones se ha presionado.

Problema:

Confeccionar un programa que tenga solo un menú de opciones que al ser presionado nos muestre un cuadro de mensaje que informe si queremos finalizar la ejecución del programa. Si se presiona "si" se finaliza el programa en caso contrario no se hace nada.

La representación visual luego de seleccionar la opción del menú es:

tkinter.messagebox askyesno

Programa: ejercicio250.py

Ver video

import tkinter as tk
from tkinter import messagebox as mb
import sys

class Aplicacion:
    def __init__(self):
        self.ventana1=tk.Tk()
        self.agregar_menu()
        self.ventana1.mainloop()

    def agregar_menu(self):
        self.menubar1 = tk.Menu(self.ventana1)
        self.ventana1.config(menu=self.menubar1)
        self.opciones1 = tk.Menu(self.menubar1, tearoff=0)
        self.opciones1.add_command(label="Salir", command=self.salir)
        self.menubar1.add_cascade(label="Opciones", menu=self.opciones1)    

    def salir(self):
        respuesta=mb.askyesno("Cuidado", "¿Quiere salir del programa?")
        if respuesta==True:
            sys.exit()
        

aplicacion1=Aplicacion() 

Cuando se selecciona la opción "Salir" del menú se ejecuta el método 'salir':

        self.opciones1.add_command(label="Salir", command=self.salir)

En el método 'salir' llamamos a la función 'askyesno' del paquete 'messagebox':

    def salir(self):
        respuesta=mb.askyesno("Cuidado", "¿Quiere salir del programa?")
        if respuesta==True:
            sys.exit()

La función 'askyesno' retorna True o False según cual de los botones se ha presionado. Si retorna True significa que se presionó el botón 'Si'