GuiMaker: автоматизация создания меню и панелей инструментов

guimaker avtomatizaciya sozdaniya menju i panelej instrumentov Приемы программирования графических интерфейсов

Подмешиваемый класс из предыдущего раздела упрощает выполнение стандартных задач, но не решает проблем сложности связывания в таких виджетах, как меню и панели инструментов. Конечно, при наличии инструмента структурирования графического интерфейса, который генерировал бы программный код на языке Python, проблем бы не было. Мы бы проектировали виджеты интерактивно, нажимали кнопку и добавляли бы реализацию обработчиков.

Однако при использовании такого относительно простого инструмента, как tkinter, сгодится и подход, основанный на программировании. Хотелось бы иметь возможность, имея в окне шаблон для меню и панелей инструментов, наследовать некоторый класс, который сам выполнял бы всю черновую работу по конструированию. Ниже демонстрируется один из возможных способов, использующий деревья простых объектов. Класс в примере 10.3 интерпретирует структуры данных, содержащих представление меню и панелей инструментов, и автоматически создает необходимые виджеты.

Пример 10.3. PP4E\Gui\Tools\guimaker.py

############################################################################## Расширенный Frame, автоматически создающий меню и панели инструментов в окне. GuiMakerFrameMenu предназначен для встраивания компонентов (создает меню на основе фреймов).

GuiMakerWindowMenu предназначен для окон верхнего уровня (создает меню Tk8.0). Пример древовидной структуры приводится в реализации самотестирования (и в PyEdit).

##############################################################################

import sys

from tkinter import * # классы виджетов

from tkinter.messagebox import showinfo

class GuiMaker(Frame):

menuBar = [] # значения по умолчанию

toolBar = [] # изменять при создании подклассов

helpButton = True # устанавливать в start()

def __init__(self, parent=None):

Frame.__init__(self, parent)

self.pack(expand=YES, fill=BOTH) # растягиваемый фрейм

self.start() # в подклассе: установить меню/панель инстр.

self.makeMenuBar() # здесь: создать полосу меню

self.makeToolBar() # здесь: создать панель инструментов

self.makeWidgets() # в подклассе: добавить середину

def makeMenuBar(self):

создает полосу меню вверху (реализация меню Tk8.0 приводится ниже) expand=no, fill=x, чтобы ширина оставалась постоянной

menubar = Frame(self, relief=RAISED, bd=2)

menubar.pack(side=TOP, fill=X)

for (name, key, items) in self.menuBar:

mbutton = Menubutton(menubar, text=name, underline=key) mbutton.pack(side=LEFT)

pulldown = Menu(mbutton) self.addMenuItems(pulldown, items) mbutton.config(menu=pulldown)

if self.helpButton:

Button(menubar, text = ‘Help’, cursor = ‘gumby’, relief = FLAT, command = self.help).pack(side=RIGHT)

def addMenuItems(self, menu, items): for item in items: # сканировать список вложенных элем.

if item == separator’: # строка: добавить разделитель

menu.add_separator({})

elif type(item) == list: # список: неактивных элементов for num in item:

menu.entryconfig(num, state=DISABLED)

elif type(item[2]) != list:

menu.add_command(label = item[0], # команда: метка underline = item[1], # горячая клавиша command = item[2]) # обрк: вызыв. объект

else:

pullover = Menu(menu)

self.addMenuItems(pullover, item[2]) # подменю:

menu.add_cascade(label = item[0], # создать подменю

underline = item[1], # добавить каскад

menu = pullover)

def makeToolBar(self):

создает панель с кнопками внизу, если необходимо expand=no, fill=x, чтобы ширина оставалась постоянной можно добавить поддержку изображений: смотрите главу 9, для чего придется создать минатюры в формате FIF или использовать расширение PIL

if self.toolBar:

toolbar = Frame(self, cursor=’hand2’, relief=SUNKEN, bd=2) toolbar.pack(side=BOTTOM, fill=X)

for (name, action, where) in self.toolBar: Button(toolbar, text=name, command=action).pack(where)

def makeWidgets(self):

‘средняя’ часть создается последней, поэтому меню/панель инструментов всегда остаются вверху/внизу и обрезаются в последнюю очередь;

переопределите этот метод,

для pack: прикрепляйте середину к любому краю;

для grid: компонуйте середину по сетке во фрейме, который прикрепляется методом pack

name = Label(self, width=40, height=10, relief=SUNKEN, bg=’white’, text = self.__class__.__name__, cursor = ‘crosshair’)

name.pack(expand=YES, fill=BOTH, side=TOP)

def help(self):

“переопределите в подклассе”

showinfo(‘Help’, ‘Sorry, no help for ‘ + self.__class__.__name__)

def start(self):

“переопределите в подклассе: связать меню/панель инструментов с selfpass

############################################################################## # Специализированная версия для полосы меню главного окна Tk 8.0

##############################################################################

GuiMakerFrameMenu = GuiMaker # используется для меню встраиваемых # компонентов

class GuiMakerWindowMenu(GuiMaker): # используется для меню окна def makeMenuBar(self): # верхнего уровня

menubar = Menu(self.master) self.master.config(menu=menubar)

for (name, key, items) in self.menuBar:

pulldown = Menu(menubar) self.addMenuItems(pulldown, items) menubar.add_cascade(label=name, underline=key, menu=pulldown)

if self.helpButton:

if sys.platform[:3] == ‘win’:

menubar.add_command(label=’Help’, command=self.help) else:

pulldown = Menu(menubar) # В Linux требуется настоящее меню pulldown.add_command(label=’About’, command=self.help) menubar.add_cascade(label=’Help’, menu=pulldown)

############################################################################## # Реализация самотестирования, которая выполняется, если запустить модуль как # самостоятельный сценарий: python guimaker.py

##############################################################################

if __name__ == ‘__main__’:

from guimixin import GuiMixin # встроить метод help

menuBar = [

(‘File’, 0,

[(‘Open’, 0, lambda:0), # lambda:0 пустая операция

(‘Quit’, 0, sys.exit)]), # здесь использовать sys, а не self (‘Edit’, 0,

[(‘Cut’, 0, lambda:0),

(‘Paste’, 0, lambda:0)]) ]

toolBar = [(‘Quit’, sys.exit, {‘side’: LEFT})]

class TestAppFrameMenu(GuiMixin, GuiMakerFrameMenu): def start(self):

self.menuBar = menuBar self.toolBar = toolBar

class TestAppWindowMenu(GuiMixin, GuiMakerWindowMenu): def start(self):

self.menuBar = menuBar self.toolBar = toolBar

class TestAppWindowMenuBasic(GuiMakerWindowMenu): def start(self):

self.menuBar = menuBar

self.toolBar = toolBar # help из GuiMaker, а не из GuiMixin

root = Tk()

TestAppFrameMenu(Toplevel())

TestAppWindowMenu(Toplevel())

TestAppWindowMenuBasic(root) root.mainloop()

Чтобы понять принцип действия этого модуля, необходимо знакомство с основами создания меню, изложенными в главе 9. При соблюдении этого условия программный код будет прост и понятен: класс GuiMaker просто выполняет обход структур с описанием меню и панели инструментов и попутно создает соответствующие виджеты. В реализацию самотестирования этого модуля включен простой пример структур данных, использованных для компоновки меню и панели инструментов:

Шаблоны меню

Списки и вложенные подсписки кортежей (метка, горячая_клави- ша, обработчик). Если обработчик является подсписком, а не функцией или методом, предполагается, что это каскадное подменю.

Шаблоны панелей инструментов

Список кортежей (метка, обработчик, параметры_компоновки). Параметры компоновки определяются в виде словаря параметров, передаваемых методу pack виджета, — словарь можно записать в виде литерала {‘k’:v} или использовать вызов функции dict(k=v) с именованными аргументами. Метод pack принимает словари, однако словари можно трансформировать в именованные аргументы, используя синтаксис вызова func(**kargs). В данной реализации метки определяются как текст, но точно так же можно было бы реализовать поддержку изображений (смотрите раздел «BigGui: клиентская демонстрационная программа» ниже)

Для разнообразия предусмотрено изменение внешнего вида указателя мыши в зависимости от его местоположения: при наведении на панель инструментов указатель приобретает вид руки, в средней части — вид перекрестия, а при наведении на кнопку Help в меню, основанном на фрейме, — другой вид (можете настроить по вашему желанию).

Использованная литература:
Марк Лутц — Программирование на Python, 4-е издание, I том, 2011

Каталог сайтов Всего.ру
Оцените статью
Секреты программирования
Добавить комментарий