# Menu — виджет меню
Меню – это виджет, который присутствует во многих пользовательских приложениях. Находится оно под строкой заголовка и представляет собой выпадающие списки под словами — пунктами меню. Пункты конечных списков представляют собой команды, обычно выполняющие какое-либо действия или открывающие диалоговые окна.
Меню может содержать много элементов, причем эти элементы сами могут представлять меню и содержать другие элементы. В зависимости от того, какой тип элементов мы хотим добавить в меню, будет отличаться метод, используемый для их добавления. В частности, нам доступны следующие методы:
- add_command(options): добавляет элемент меню через параметр options
- add_cascade(options): добавляет элемент меню, который в свою очередь может представлять подменю
- add_separator(): добавляет линию-разграничитель
- add_radiobutton(options): добавляет в меню переключатель
- add_checkbutton(options): добавляет в меню флажок
# 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, связав тем самым с какой-либо функцией-обработчиком клика. Хотя такой вариант меню имеет право на существование, в большинстве приложений панель меню содержит выпадающие списки команд, а сами пункты на панели командами по сути не являются. Клик по ним приводит лишь к раскрытию соответствующего списка.
# Упражнения
- Создайте визуально похожее меню программы блокнот или skype.
- Реализуйте генерацию меню. Образец меню записан в виде массива:
menu_example = [ ['file', ['new', 'open', 'close']], ['edit', ['undo', 'cut', 'paste', 'delete']], ['format', ['word wrap', 'font']], ['view', ['zoom', 'status bar']], ['help', ['view help', 'about notepad']] ]
# Подменю — Submenu
Подменю — это меню, подключенное к другому объекту меню.
В 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() добавляет линию разделитель в меню. Используется для визуального разделения групп команд.
# Взаимодействие с меню
Отличительной особенностью элементов меню является способность реагировать на нажатия пользователя. Для этого у каждого элемента меню можно задать параметр command , который устанавливает ссылку на функцию, выполняемую при нажатии:
from tkinter import * from tkinter import messagebox def edit_click(): messagebox.showinfo("GUI Python", "Нажата опция Edit") root = Tk() root.title("GUI на Python") root.geometry("300x250") main_menu = Menu() main_menu.add_cascade(label="File") main_menu.add_cascade(label="Edit", command=edit_click) main_menu.add_cascade(label="View") root.config(menu=main_menu) root.mainloop()
# Контекстное меню — Popup menu
В следующем примере мы создаем всплывающее меню. Всплывающее меню также называется контекстным меню. Это может быть показано в любом месте на клиентской области окна:
from tkinter import * def showMenu(event): print(event) menu.post(event.x_root, event.y_root) def onQuit(): quit() root = Tk() root.geometry("250x150+300+300") root.title("Popup menu") menu = Menu(root, tearoff=0) menu.add_command(label="Exit", command=root.destroy) menu.add_command(label="Quit", command=onQuit) root.bind("", showMenu) root.mainloop()
В нашем примере мы создаем всплывающее меню с двумя командами:
- контекстное меню — это обычный виджет меню. Функция отрыва отключена. Теперь невозможно разделить меню на новое окно верхнего уровня:
- Мы связываем событие с методом showMenu() . Событие генерируется, когда мы щелкаем правой кнопкой мыши на клиентской области окна:
- Метод showMenu() показывает контекстное меню. Всплывающее меню отображается в координатах x и y щелчка мыши:
def showMenu(event): print(event) menu.post(event.x_root, event.y_root)
Результат выполнения может:
В tkinter можно создать всплывающее меню и настроить его появление по клику правой кнопкой мыши. Для этого экземпляр меню подвязывается не через опцию menu к родительскому виджету, а к меню применяется метод post() , аргументами которого являются координаты того места, где должно появляться меню:
from tkinter import * x = 0 y = 0 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) root = Tk() c = Canvas(width=300, height=300, bg='white') c.pack() menu = Menu(tearoff=0) menu.add_command(label="Круг", command=circle) menu.add_command(label="Квадрат", command=square) menu.add_command(label="Треугольник", command=triangle) c.bind("", popup) root.mainloop()
Здесь при клике на холсте правой кнопкой мыши в этой точке всплывает меню. При выборе пункта меню рисуется соответствующая фигура в этом же месте.
# Упражнения
- Напишите визуальное подобие простейшего текстового редактора, например программы Блокнот.
- Реализуйте главное меню File добавив кнопки: open , save и close .
- Реализуйте работу кнопок ( open , save и close ) используя диалоговые окна.
- Добавьте текстовое поле с корректным отображением при масштабировании окна.
- Добавьте вызов контекстного меню с командами: cut , copy и paste .
- Реализуйте работу кнопок ( cut , copy и paste ), обратившись к свойствам текстового поля.
- Реализуйте функцию кнопки меню «переноса текста»: при активации перенос текста происходит по словам.
Меню для программы python
Для создания иерархического меню в tkinter применяется виджет Menu . Основные параметры Menu:
- activebackground : цвет активного пункта меню
- activeborderwidth : толщина границы активного пункта меню
- activeforeground : цвет текста активного пункта меню
- background / bg : фоновый цвет
- bd : толщина границы
- cursor : курсор указателя мыши при наведении на меню
- disabledforeground : цвет, когда меню находится в состоянии DISABLED
- font : шрифт текста
- foreground / fg : цвет текста
- tearoff : меню может быть отсоединено от графического окна. В частности, при создании подменю а скриншоте можно увидеть прерывающуюся линию в верху подменю, за которую его можно отсоединить. Однако при значении tearoff=0 подменю не сможет быть отсоединено.
Меню может содержать много элементов, причем эти элементы сами могут представлять меню и содержать другие элементы. В зависимости от того, какой тип элементов мы хотим добавить в меню, будет отличаться метод, используемый для их добавления. В частности, нам доступны следующие методы:
- add_command(options) : добавляет элемент меню через параметр options
- add_cascade(options) : добавляет элемент меню, который в свою очередь может представлять подменю
- add_separator() : добавляет линию-разграничитель
- add_radiobutton(options) : добавляет в меню переключатель
- add_checkbutton(options) : добавляет в меню флажок
from tkinter import * root = Tk() root.title("METANIT.COM") root.geometry("250x150") main_menu = Menu() main_menu.add_cascade(label="File") main_menu.add_cascade(label="Edit") main_menu.add_cascade(label="View") root.config(menu=main_menu) root.mainloop()
Для добавления пунктов меню у объекта Menu вызывается метод add_cascade() . В этот метод передаются параметры пункта меню, в данном случае они представлены текстовой меткой, устанавливаемой через параметр label .
Но просто создать меню — еще недостаточно. Его надо установить для текущего окна с помощью параметра menu в методе config() . В итоге графическое окно будет иметь следующее меню:
from tkinter import * root = Tk() root.title("METANIT.COM") root.geometry("250x150") main_menu = Menu() file_menu = Menu() file_menu.add_command(label="New") file_menu.add_command(label="Save") file_menu.add_command(label="Open") file_menu.add_separator() file_menu.add_command(label="Exit") main_menu.add_cascade(label="File", menu=file_menu) main_menu.add_cascade(label="Edit") main_menu.add_cascade(label="View") root.config(menu=main_menu) root.mainloop()
Здесь определяется подменю file_menu, которое добавляется в первый пункт основного меню благодаря установке опции menu=file_menu :
main_menu.add_cascade(label="File", menu=file_menu)
Но обратите внимание на пунктирную линию в подменю, которая совершенно не нужна и непонятно откуда появляется. Чтобы избавиться от этой линии, надо для нужного пункта меню установить параметр tearoff=0 :
Однако так как подпунктов меню может быть много, чтобы для кажлого не прописывать этот параметр, то проще отключить все это глобально с помощью следующей строки кода
root.option_add("*tearOff", FALSE)
from tkinter import * root = Tk() root.title("METANIT.COM") root.geometry("250x150") root.option_add("*tearOff", FALSE) main_menu = Menu() file_menu = Menu() file_menu.add_command(label="New") file_menu.add_command(label="Save") file_menu.add_command(label="Open") file_menu.add_separator() file_menu.add_command(label="Exit") main_menu.add_cascade(label="File", menu=file_menu) main_menu.add_cascade(label="Edit") main_menu.add_cascade(label="View") root.config(menu=main_menu) root.mainloop()
Подобным образом можно создавать и более глубокие иерархии меню:
from tkinter import * root = Tk() root.title("METANIT.COM") root.geometry("250x150") root.option_add("*tearOff", FALSE) main_menu = Menu() file_menu = Menu() settings_menu = Menu() settings_menu.add_command(label="Save") settings_menu.add_command(label="Open") file_menu.add_cascade(label="Settings", menu=settings_menu) file_menu.add_separator() file_menu.add_command(label="Exit") main_menu.add_cascade(label="File", menu=file_menu) root.config(menu=main_menu) root.mainloop()
Взаимодействие с меню
Отличительной особенностью элементов меню является способность реагировать на нажатия пользователя. Для этого у каждого элемента меню можно задать параметр command , который устанавливает ссылку на функцию, выполняемую при нажатии.
from tkinter import * from tkinter import messagebox root = Tk() root.title("METANIT.COM") root.geometry("250x150") root.option_add("*tearOff", FALSE) def edit_click(): messagebox.showinfo("GUI Python", "Нажата опция Edit") main_menu = Menu() main_menu.add_cascade(label="File") main_menu.add_cascade(label="Edit", command=edit_click) main_menu.add_cascade(label="View") root.config(menu=main_menu) root.mainloop()