Виджет Menu в tkinter
Меню – это виджет, который присутствует во многих пользовательских приложениях. Находится оно под строкой заголовка и представляет собой выпадающие списки под словами-пунктами меню. Пункты конечных списков представляют собой команды, обычно выполняющие какие-либо действия или открывающие диалоговые окна.
В 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("", 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 . Команду очистки текстового поля поместите в контекстное меню.
Курс с примерами решений практических работ: pdf-версия
Tkinter. Программирование GUI на Python
Как создать выпадающее меню в Tkinter
- Tkinter OptionMenu Пример
- Привязать команду к OptionMenu When Value Changes
В Tkinter есть несколько способов создания выпадающего меню.
OptionMenu немного похоже на виджет Combobox, но уже включён в сам Tkinter, поэтому нет необходимости импортировать ttk, как в случае с Combobox .
Tkinter OptionMenu Пример
import tkinter as tk OptionList = [ "Aries", "Taurus", "Gemini", "Cancer" ] app = tk.Tk() app.geometry('100x200') variable = tk.StringVar(app) variable.set(OptionList[0]) opt = tk.OptionMenu(app, variable, *OptionList) opt.config(width=90, font=('Helvetica', 12)) opt.pack() app.mainloop()
opt = tk.OptionMenu(app, variable, *OptionList)
app является родителем созданного меню опций,
variable — это исходная текстовая переменная, имеющая тип tk.StringVar .
*OptionList — это другие опции меню. * используется для распаковки контейнера, так как здесь используется тип list .
Привязать команду к OptionMenu When Value Changes
OptionMenu не смог связать команду при выборе нового значения из списка опций. Нельзя было просто связать с ней функцию обратного вызова, как виджет кнопки.
tk.Button(app, text="Increase", width=30, command=change_label_number)
Вам нужно использовать метод трассировки, чтобы прикрепить обратные вызовы Обсервера к переменной OptionMenu . Каждый раз, когда переменная изменяется, она запускает функции обратного вызова.
Пример обратного вызова OptionMenu
import tkinter as tk OptionList = [ "Aries", "Taurus", "Gemini", "Cancer" ] app = tk.Tk() app.geometry('100x200') variable = tk.StringVar(app) variable.set(OptionList[0]) opt = tk.OptionMenu(app, variable, *OptionList) opt.config(width=90, font=('Helvetica', 12)) opt.pack(side="top") labelTest = tk.Label(text="", font=('Helvetica', 12), fg='red') labelTest.pack(side="top") def callback(*args): labelTest.configure(text="The selected item is <>".format(variable.get())) variable.trace("w", callback) app.mainloop()
Тогда variable.trace(«w», callback) означает, что она вызовет функцию callback , когда variable будет записана или выбрана пользователем.
Founder of DelftStack.com. Jinku has worked in the robotics and automotive industries for over 8 years. He sharpened his coding skills when he needed to do the automatic testing, data collection from remote servers and report creation from the endurance test. He is from an electrical/electronics engineering background but has expanded his interest to embedded electronics, embedded programming and front-/back-end programming.