Cómo crear un menú superior con Tkinter: guía paso a paso

Cómo crear un menú superior con Tkinter: guía paso a paso

¿Te gustaría aprender a crear una interfaz gráfica de usuario (GUI) con Python? ¿Quieres darle un aspecto profesional y funcional a tus aplicaciones de escritorio? Entonces este tutorial es para ti. En este artículo te enseñaré cómo crear un menú superior con tkinter, una de las bibliotecas más populares y sencillas para crear GUIs con Python. Un menú superior es una barra que se ubica en la parte superior de la ventana y que contiene diferentes opciones y funciones que el usuario puede seleccionar. Con tkinter puedes crear menús superiores de forma fácil y rápida, siguiendo unos pocos pasos que te explicaré a continuación. Además, podrás personalizar el aspecto y el comportamiento de tus menús según tus preferencias y necesidades. ¿Estáis listos para empezar? ¡Pues vamos allá!

Importar Tkinter y crear el menú

Primero, debes importar Tkinter.

# Importación de Tkinter
import tkinter as tk

Después, hay que crear un objeto de tipo menú. Este lo instanciamos de la clase "Menu" de Tkinter.

# Se crea el menú de la ventana
menu = tk.Menu()

Crear opciones principales para el menú de Tkinter

Lo siguiente que haremos, será crear objetos para cada opción principal, las típicas de Archivo, Edición, etc.

Con el primero argumento, especificamos donde aparecen (menu) y con el segundo (tearoff con 0), hacemos que el menú sea fijo, comportamiento por defecto (luego explico la opción alternativa).

Con el nombre del objeto del menú, utilizando su método add_cascade(), vamos a añadir cada uno de los objetos al menú asociándolos a una etiqueta.

# Se crean las opciones principales
menu_archivo = tk.Menu(menu, tearoff=0)
menu_editar = tk.Menu(menu, tearoff=0)
menu_ayuda = tk.Menu(menu, tearoff=0)

# Agregar las opciones principales al menú
menu.add_cascade(label="Archivo", menu=menu_archivo)
menu.add_cascade(label="Editar", menu=menu_editar)
menu.add_cascade(label="Ayuda", menu=menu_ayuda)

Crear subopciones para el menú de Tkinter

Cuando ya tengas todas las opciones principales añadidas a tu menú, le puedes añadir subopciones para que se despliegue el menú con las que necesites.

Esto lo hacemos asociando a cada objeto de opción principal una nueva etiqueta con el método add_command:

# Se crean las subopciones para "Archivo"
menu_archivo.add_command(label="Abrir")
menu_archivo.add_command(label="Guardar")
menu_archivo.add_separator()
menu_archivo.add_command(label="Salir", command=root.quit)

# Se crean las subopciones para "Editar"
menu_editar.add_command(label="Cortar")
menu_editar.add_command(label="Copiar")
menu_editar.add_command(label="Pegar")

Si quieres que una opción principal no tenga subopciones, la dejas sin "add_command", como el caso de "menu_ayuda", que no le añado ninguna opción.

Para hacer que los botones realicen acciones, utiliza el sistema de siempre con los botones de Tkinter, el "command" con la llamada a una función o método.

En el ejemplo de "Salir", he llamado al método quit() de Tkinter para que finalice el programa si se pulsa, solo para que veas un ejemplo de uso.

Ya solo queda lo último, hemos empezado la casa por el tejado. Hay que colocar el menú en la ventana, en mi caso, se llama root:

# Se muestra la barra de menú en la ventana principal
root.config(menu=menu)

Que no te confunda "menu=menu", el primero, es el nombre del atributo de la ventana root destinado a colocar un menú. El segundo, es el nombre del objeto que hemos creado. Si crees que esto crea confusión, llámalo por ejemplo "menu_superior".

Esto quedaría así:

root.config(menu=menu_superior)

Vamos a probar esto:

tkinter menú superior

El resultado es tal y como esperamos en cualquier programa.

Añadir más opciones dentro de las subopciones

Lo siguiente que puede que necesites, es añadir más opciones anidadas dentro de las subopciones. Esto es tan fácil como utilizar de nuevo "add_command" con alguna de las subopciones. En este caso, el "add_cascade" tiene que ser aplicado con la opción principal (menu_archivo, por ejemplo).

# Se crean las subopciones para "Archivo > Abrir"
menu_preferencias = tk.Menu(menu_archivo, tearoff=0)
menu_preferencias.add_command(label="Opción 1")
menu_preferencias.add_command(label="Opción 2")
menu_preferencias.add_command(label="Opción 3")

# Se añaden las subopciones de "Abrir" al menú "Archivo"
menu_archivo.add_cascade(label="Abrir", menu=menu_preferencias)

Crear menús desacopables con Tkinter

Queda solo explicar el tema del atributo "tearoff".

El atributo "tearoff" con un valor de 0, crea un menú fijo como el que acabas de ver, sin embargo, puedes hacer que un menú se pueda desacoplar con el valor 1.

He puesto en 1 estos dos elementos, el resto a 0.

menu_editar = tk.Menu(menu, tearoff=1)
...
menu_preferencias = tk.Menu(menu_archivo, tearoff=1)

El resultado es que se pueden separar esas partes del menú en pequeñas ventanas adicionales.

Menús desplegables con tkinter

Te dejo el código completo aquí por si has tenido problemas para seguir el hilo en alguna parte:

# Importación de Tkinter
import tkinter as tk

# Se crea la ventana del programa
root = tk.Tk()
# Se crea el menú de la ventana
menu = tk.Menu()

# Se crean las opciones principales
menu_archivo = tk.Menu(menu, tearoff=0)
menu_editar = tk.Menu(menu, tearoff=0)
menu_ayuda = tk.Menu(menu, tearoff=0)

# Agregar las opciones principales al menú
menu.add_cascade(label="Archivo", menu=menu_archivo)
menu.add_cascade(label="Editar", menu=menu_editar)
menu.add_cascade(label="Ayuda", menu=menu_ayuda)

# Se crean las subopciones para "Archivo"
menu_archivo.add_command(label="Abrir")
menu_archivo.add_command(label="Guardar")
menu_archivo.add_separator()
menu_archivo.add_command(label="Salir", command=root.quit)

# Se crean las subopciones para "Editar"
menu_editar.add_command(label="Cortar")
menu_editar.add_command(label="Copiar")
menu_editar.add_command(label="Pegar")

# Se crean las subopciones para "Archivo > Preferencias"
menu_preferencias = tk.Menu(menu_archivo, tearoff=0)
menu_preferencias.add_command(label="Opción 1")
menu_preferencias.add_command(label="Opción 2")
menu_preferencias.add_command(label="Opción 3")

# Se crea la cascada de "Preferencias" al menú "Archivo"
menu_archivo.add_cascade(label="Preferencias", menu=menu_preferencias)

# Se muestra la barra de menú en la ventana principal
root.config(menu=menu)

# Bucle de ejecución del programa
root.mainloop()

Adaptar los menús de Tkinter a CustomTkinter

Para quienes utilizáis CustomTkinter, tengo una mala noticia, no tiene menús superiores, hay que utilizar los propios de Tkinter.

Pues bien, hago esta última sección para que veáis de qué forma podéis crear un menú superior de Tkinter en una ventana de tipo CTk e CustomTkinter.

La forma de hacer esto, es más engorrosa, ya que tenemos que crear los botones del menú por nuestra cuenta.

Primero, en la línea 10, creo un frame para el menú. Lo posiciono en la parte superior.

Después, en la línea 15 hago uso de una cosa nueva de Tkinter, los Menubutton, que son botones sueltos de menú.

Con estos Menubutton, podemos ir creando la barra de menú superior.

Lo bueno de usarlos, es que permiten personalizarse de manera relativamente fácil, cosa que no podemos hacer con el menú nativo de Windows (en donde estoy explicando) que utiliza Tkinter.

En la línea 21 y 22, creo menús desplegables para cada Menubutton.

Después, ya podemos ir añadiendo opciones con "add_command()" a los menús.

# Se importa Tkinter
import tkinter as tk

# Se crea la ventana con un tamaño y color de fondo
root = tk.Tk()
root.geometry("400x200")
root.config(background="gray17")

# Se crea un frame para contener el menu
menu_frame = tk.Frame(root, background='black')
# Posiciona el Frame en la parte superior de la ventana
menu_frame.pack(side='top', fill='x')

# Crea un Menubutton dentro del Frame
archivo = tk.Menubutton(menu_frame, 
                        text='Archivo', 
                        background='black', 
                        foreground='white', 
                        activeforeground='black', 
                        activebackground='gray52')

# Crea un Menubutton dentro del Frame
edicion = tk.Menubutton(menu_frame, text='Edición', 
                        background='black', 
                        foreground='white',
                        activeforeground='black', 
                        activebackground='gray52')

# Crea un menú desplegable para el Menubutton
menu_archivo = tk.Menu(archivo, tearoff=0)
menu_edicion = tk.Menu(edicion, tearoff=0)

# Agrega una opción al menú desplegable
menu_archivo.add_command(label='Imprimir', 
                         command=lambda: print('Hello PC Master!'), 
                         background='black', 
                         foreground='white', 
                         activeforeground='black', 
                         activebackground='gray52')

# Asigna el menú desplegable al Menubutton
archivo.config(menu=menu_archivo)
# Posiciona el Menubutton dentro del Frame
archivo.pack(side='left')

root.mainloop()

Para quienes seguís el proyecto que estoy realizando en este curso, os dejo una adaptación de un menú en la interfaz de este.

Si no estás siguiendo este curso, ignora este código.

El color es para el modo oscuro. Aquí ya hay que añadir trabajo extra al utilizar CustomTkinter, ya que deberíamos crear dos menús solo para los dos modos de color.

En el vídeo de arriba explico mucho más:

class VentanaOpciones:
    # Diccionario para los botones
    botones = {'Consulta SQL': objeto_funciones.ventana_consultas, 
               'Mostrar Bases de Datos': objeto_funciones.ventana_mostrar_bases_datos,
               'Eliminar Bases de Datos': objeto_funciones.ventana_eliminar_bases_datos,
               'Crear Bases de Datos': objeto_funciones.ventana_crear_bases_datos, 
               'Crear Respaldos': objeto_funciones.ventana_crear_respaldos,
               'Crear Tablas': objeto_funciones.ventana_crear_tablas,
               'Eliminar Tablas': objeto_funciones.ventana_eliminar_tablas,
               'Mostrar Tablas': objeto_funciones.ventana_mostrar_tablas,
               'Mostrar Columnas': objeto_funciones.ventana_mostrar_columnas,
               'Insertar Registros': objeto_funciones.ventana_insertar_registros,
               'Eliminar Registros': objeto_funciones.ventana_eliminar_registros,
               'Vaciar Tablas': objeto_funciones.ventana_vaciar_tablas,
               'Actualizar Registros': objeto_funciones.ventana_actualizar_tablas
               }
    def __init__(self):
        # Se crea la ventana de CustomTkinter
        self.root = ctk.CTk()
        # Se le da un título
        self.root.title("Opciones para trabajar con bases de datos.")
    
        # Marco para contener el menú superior
        menu_frame = ctk.CTkFrame(self.root)
        menu_frame.pack(side='top', fill='x')

        # Se crea el botón de Menú
        archivo = tk.Menubutton(menu_frame, 
                                text='Archivo', 
                                background='#2b2b2b', 
                                foreground='white', 
                                activeforeground='black', 
                                activebackground='gray52')
        
        # Se crea el botón de Menú
        edicion = tk.Menubutton(menu_frame, 
                                text='Edición', 
                                background='#2b2b2b', 
                                foreground='white', 
                                activeforeground='black', 
                                activebackground='gray52')
        
        # Se crea el menú
        menu_archivo = tk.Menu(archivo, tearoff=0)
        # Se crea el menú
        menu_edicion = tk.Menu(edicion, tearoff=0)

        # Añade una opción al menú desplegable
        menu_archivo.add_command(label='Imprimir Saludo', 
                                 command=lambda: print('Hello PC Master!'), 
                                 background='#2b2b2b', 
                                 foreground='white', 
                                 activeforeground='black', 
                                 activebackground='gray52')
        
        
        # Crea un nuevo menú para la cascada
        cascada = tk.Menubutton(menu_edicion, 
                                text='Cascada', 
                                background='black', 
                                foreground='white', 
                                activeforeground='black', 
                                activebackground='gray52')
        
        # Se crea el menú
        menu_cascada = tk.Menu(cascada, tearoff=0)
        cascada.config(menu=menu_cascada)
        
        # Se crea una cascada dentro del menu de edición
        menu_edicion.add_cascade(label="Opciones", menu=menu_cascada, 
                                 background='#2b2b2b', 
                                 foreground='white', 
                                 activeforeground='black', 
                                 activebackground='gray52')
    
        # Agrega opciones a la cascada
        menu_cascada.add_command(label="Opción 1", 
                                 command=lambda: print("Opción 1 seleccionada"), 
                                 background='#2b2b2b', 
                                 foreground='white', 
                                 activeforeground='black', 
                                 activebackground='gray52')
        
        menu_cascada.add_command(label="Opción 2", 
                                 command=lambda: print("Opción 2 seleccionada"), 
                                 background='#2b2b2b', 
                                 foreground='white', 
                                 activeforeground='black', 
                                 activebackground='gray52')
        
        menu_cascada.add_command(label="Opción 3", 
                                 command=lambda: print("Opción 3 seleccionada"), 
                                 background='#2b2b2b', 
                                 foreground='white', 
                                 activeforeground='black', 
                                 activebackground='gray52')
        
        # Asigna el menú desplegable al Menubutton
        archivo.config(menu=menu_archivo)
        # Posiciona el Menubutton dentro del Frame
        archivo.pack(side='left')
        
        # Asigna el menú desplegable al Menubutton
        edicion.config(menu=menu_edicion)
        # Posiciona el Menubutton dentro del Frame
        edicion.pack(side='left')
        
        # Asigna el menú desplegable al Menubutton
        cascada.config(menu=menu_cascada)
        
        # Crea un Frame para contener los botones de la ventana
        frame_botones = ctk.CTkFrame(self.root)
        # Posiciona el Frame debajo del menú
        frame_botones.pack(side='top', fill='x')

        # Contador para la posición de los botones
        contador = 0

        # Valor de elementos por fila
        elementos_fila = 3

        # Crea los botones y establece su texto
        for texto_boton in self.botones:
            boton = ctk.CTkButton(
                master=frame_botones, #Se le indica en que frame aparecer
                text=texto_boton,
                height=25,
                width=200,
                command=self.botones[texto_boton]
            )
            boton.grid(row=contador//elementos_fila, column=contador%elementos_fila, padx=5, pady=5)

            # Incrementa el contador
            contador += 1

        self.root.mainloop()

No te pierdas nada del curso Máster en Python.

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *

curso sql Entrada anterior Ejercicios resueltos para practicar SQL
protocolo http Entrada siguiente Protocolo HTTP: ¿Cómo se comunican los clientes web y los servidores?