Хотя это не совсем обычно для окон верхнего уровня, но допустимо создание строки меню в виде горизонтального фрейма Frame. Однако прежде чем показывать, как это делается, я хочу объяснить, зачем это может понадобиться. Поскольку такая схема, основанная на фреймах, не зависит от протоколов окон верхнего уровня, она может применяться для добавления меню в качестве вложенных компонентов более крупных интерфейсов. Иными словами, она в основном применяется не к окнам верхнего уровня. Например, текстовый редактор PyEdit из главы 11 может использоваться как программа и как прикрепляемый компонент. Мы реализуем выбор в PyEdit с помощью оконных меню при выполнении его как самостоятельной программы и с помощью меню, основанного на фрейме, когда PyEdit будет встраиваться в интерфейсы PyMailGUI и PyView. Поэтому стоит знать обе схемы.
Для меню на основе фреймов требуется написать несколько дополнительных строчек программного кода, но они ненамного сложнее оконных меню. Для создания такого меню нужно разместить виджеты Menubutton в контейнере Frame, связать виджеты Menu и Menubutton и присоединить Frame к верхней части окна-контейнера. В примере 9.3 создается такое же меню, как в примере 9.2, но с использованием фрейма.
Пример 9.3. PP4E\Gui\Tour\menu_frm.py
# Меню на основе фреймов: пригодно для окон верхнего уровня и компонентов
from tkinter import * # импортировать базовый набор виджетов
from tkinter.messagebox import * # импортировать стандартные диалоги
def notdone():
showerror(‘Not implemented’, ‘Not yet available’)
def makemenu(parent):
menubar = Frame(parent) # relief=RAISED, bd=2…
menubar.pack(side=TOP, fill=X)
fbutton = Menubutton(menubar, text=’File’, underline=0) fbutton.pack(side=LEFT) file = Menu(fbutton)
file.add_command(label=’New…’, command=notdone, underline=0) file.add_command(label=’Open…’, command=notdone, underline=0) file.add_command(label=’Quit’, command=parent.quit, underline=0) fbutton.config(menu=file)
ebutton = Menubutton(menubar, text=’Edit’, underline=0) ebutton.pack(side=LEFT)
edit = Menu(ebutton, tearoff=False)
edit.add_command(label=’Cut’, command=notdone, underline=0) edit.add_command(label=’Paste’, command=notdone, underline=0) edit.add_separator() ebutton.config(menu=edit)
submenu = Menu(edit, tearoff=True)
submenu.add_command(label=’Spam’, command=parent.quit, underline=0) submenu.add_command(label=’Eggs’, command=notdone, underline=0) edit.add_cascade(label=’Stuff’, menu=submenu, underline=0) return menubar
if __name__ == ‘__main__’:
root = Tk() # или TopLevel, или Frame
root.title(‘menu_frm’) # информация для менеджера окон
makemenu(root) # создать строку меню
msg = Label(root, text=’Frame menu basics’) # добавить что-нибудь ниже msg.pack(expand=YES, fill=BOTH) msg.config(relief=SUNKEN, width=40, height=7, bg=’beige’) root.mainloop()
Снова выделим здесь логику связывания, чтобы не отвлекали другие детали. Для меню File она сводится к следующему:
menubar = Frame(parent) # создать Frame для строки меню
fbutton = Menubutton(menubar, text=’File’) # прикрепить Menubutton к Frame file = Menu(fbutton) # прикрепить Menu к Menubutton
fbutton.config(menu=file) # связать кнопку и меню
В этой схеме появился дополнительный виджет Menubutton, но это не сделало ее намного сложнее создания оконных меню верхнего уровня. На рис. 9.5 и 9.6 изображено, как этот сценарий выполняется в Windows.
Рис. 9.5. Сценарий menu_frm: фрейм и полоса меню Menubutton
Виджеты меню в этом сценарии по умолчанию предоставляют набор связанных событий, автоматически отображающих меню при выборе мышью. Такие внешний вид и поведение не вполне совпадают с продемонстрированной выше схемой оконного меню верхнего уровня, хотя
Рис. 9.6. С выбранным меню Edit
и близки к ней; виджеты могут настраиваться теми способами, которые допускают фреймы (то есть с помощью цветов и границ), и будут иметь одинаковый внешний вид на всех платформах (что, возможно, является недостатком).
Однако самым большим преимуществом строк меню на основе фреймов является возможность прикрепления в качестве вложенных компонентов к более крупным интерфейсам. Пример 9.4 и создаваемый им интерфейс (рис. 9.7) показывают, каким образом это делается, — обе полосы меню в одном окне полностью функциональны.
Рис. 9.7. Несколько меню на основе фреймов в одном окне
Пример 9.4. PP4E\Gui\Tour\menu_frm-multi.py
from menu_frm import makemenu # здесь нельзя использовать menu_win—одно окно from tkinter import * # но можно прикреплять меню на основе фреймов
root = Tk()
for i in range(2): # 2 меню в одном окне
mnu = makemenu(root)
mnu.config(bd=2, relief=RAISED)
Label(root, bg=’black’, height=5, width=25).pack(expand=YES, fill=BOTH)
Button(root, text=”Bye”, command=root.quit).pack() root.mainloop()
Благодаря отсутствию привязки к охватывающему окну меню на основе фреймов можно использовать в составе другого прикрепляемого компонента. Например, прием встраивания меню, представленный в примере 9.5, действует, даже когда родителем меню является другой контейнер Frame, а не окно верхнего уровня. Этот сценарий похож на предыдущий, но он создает три полнофункциональных строки меню, прикрепленных к фреймам внутри окна.
Пример 9.5. PP4E\Gui\Tour\menu_frm-multi2.py
from menu_frm import makemenu # нельзя использовать menu_win—kopeHb=Frame from tkinter import *
root = Tk()
for i in range(3): # три меню, вложенные в контейнеры
frm = Frame()
mnu = makemenu(frm)
mnu.config(bd=2, relief=RAISED)
frm.pack(expand=YES, fill=BOTH)
Label(frm, bg=’black’, height=5, width=25).pack(expand=YES, fill=BOTH)
Button(root, text=”Bye”, command=root.quit).pack() root.mainloop()
Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011