Виджет Menu

Меню – это виджет, который присутствует во многих пользовательских приложениях. Находится оно под строкой заголовка и представляет собой выпадающие списки под словами-пунктами меню. Пункты конечных списков представляют собой команды, обычно выполняющие какое-либо действия или открывающие диалоговые окна.

В tkinter экземпляр меню создается от класса Menu, далее его надо привязать к виджету, на котором оно будет расположено. Обычно таковым выступает главное окно приложения. Его опции menu присваивается экземпляр Menu через имя связанной с экземпляром переменной.

from tkinter import *
 
root = Tk()
mainmenu = Menu(root) 
root.config(menu=mainmenu) 
 
root.mainloop() 

Если выполнить данный код, то никакого меню вы не увидите. Только тонкую полоску под заголовком окна, ведь ни одного пункта меню не было создано. Метод add_command добавляет пункт меню:

… 
mainmenu.add_command(label='Файл')
mainmenu.add_command(label='Справка')

В данном случае "Файл" и "Справка" – это команды. К ним можно добавить опцию command, связав тем самым с какой-либо функцией-обработчиком клика. Хотя такой вариант меню имеет право на существование, в большинстве приложений панель меню содержит выпадающие списки команд, а сами пункты на панели командами по сути не являются. Клик по ним приводит лишь к раскрытию соответствующего списка.

В Tkinter проблема решается созданием новых экземпляров Menu и подвязыванием их к главному меню с помощью метода add_cascade.

from tkinter import *
 
root = Tk()
 
mainmenu = Menu(root) 
root.config(menu=mainmenu) 
 
filemenu = Menu(mainmenu, tearoff=0)
filemenu.add_command(label="Открыть...")
filemenu.add_command(label="Новый")
filemenu.add_command(label="Сохранить...")
filemenu.add_command(label="Выход")
 
helpmenu = Menu(mainmenu, tearoff=0)
helpmenu.add_command(label="Помощь")
helpmenu.add_command(label="О программе")
 
mainmenu.add_cascade(label="Файл",
                     menu=filemenu)
mainmenu.add_cascade(label="Справка",
                     menu=helpmenu)
 
root.mainloop() 

На основное меню mainmenu, добавляются не команды, а другие меню. У filemenu и helpmenu в качестве родительского виджета указывается не root, а mainmenu. Команды добавляются только к дочерним меню. Значение 0 опции tearoff отключает возможность открепления подменю, иначе его можно было бы делать плавающим кликом мыши по специальной линии. В случае tearoff=0 она отсутствует.

Точно также можно подвязывать дочерние меню к filemenu и helpmenu, создавая многоуровневые списки пунктов меню.

… 
helpmenu = Menu(mainmenu, tearoff=0)
 
helpmenu2 = Menu(helpmenu, tearoff=0)
helpmenu2.add_command(
    label="Локальная справка")
helpmenu2.add_command(
    label="На сайте")
 
helpmenu.add_cascade(label="Помощь",
                     menu=helpmenu2)
 
helpmenu.add_command(label="О программе")

Метод add_separator добавляет линию разделитель в меню. Используется для визуального разделения групп команд.

В tkinter можно создать всплывающее меню, оно же контекстное (если настроить его появление по клику правой кнопкой мыши). Для этого экземпляр меню подвязывается не через опцию menu к родительскому виджету, а к меню применяется метод post, аргументами которого являются координаты того места, где должно появляться меню.

from tkinter import *
 
 
def circle():
    c.create_oval(
        x, y, x + 30, y + 30)
 
 
def square():
    c.create_rectangle(
        x, y, x + 30, y + 30)
 
 
def triangle():
    c.create_polygon(
        x, y, x - 15, y + 30, x + 15, y + 30,
        fill='white', outline='black')
 
 
def popup(event):
    global x, y
    x = event.x
    y = event.y
    menu.post(event.x_root, event.y_root)
 
 
x = 0
y = 0
 
root = Tk()
c = Canvas(width=300, height=300, bg='white')
c.pack()
c.bind("<Button-3>", popup)
menu = Menu(tearoff=0)
menu.add_command(label="Круг", 
                 command=circle)
menu.add_command(label="Квадрат", 
                 command=square)
menu.add_command(label="Треугольник", 
                 command=triangle)
root.mainloop()
 

Здесь при клике на холсте правой кнопкой мыши в этой точке всплывает меню. При выборе пункта меню рисуется соответствующая фигура в этом же месте.

Практическая работа

Измените программу из практической работы предыдущего урока так, чтобы открытие и сохранение файлов выполнялось не через экземпляры Button, а через Menu. Команду очистки текстового поля поместите в контекстное меню.

Курс с примерами решений практических работ: android-приложение, pdf-версия.

Tkinter. Программирование GUI на Python