Введение
В этом практическом занятии вы научитесь создавать простое меню с использованием Matplotlib. Меню будет содержать список элементов, каждый из которых может быть выбран пользователем. Выбранный элемент затем вызовет функцию обратного вызова, которая выполнит какое-то действие.
Советы по работе с ВМ
После запуска ВМ перейдите в левый верхний угол и переключитесь на вкладку Notebook, чтобы приступить к практике в Jupyter Notebook.
Иногда вам может потребоваться подождать несколько секунд, пока Jupyter Notebook не загрузится полностью. Валидация операций не может быть автоматизирована из-за ограничений Jupyter Notebook.
Если вы сталкиваетесь с проблемами во время обучения, не стесняйтесь обращаться к Labby. Оставьте отзыв после занятия, и мы оперативно решим проблему для вас.
Импорт библиотек
Для начала работы нам нужно импортировать необходимые библиотеки. В данном случае нам нужно импортировать matplotlib.pyplot, matplotlib.artist, matplotlib.patches и IdentityTransform из matplotlib.transforms.
import matplotlib.pyplot as plt
import matplotlib.artist as artist
import matplotlib.patches as patches
from matplotlib.transforms import IdentityTransform
Определение класса ItemProperties
Далее мы определяем класс ItemProperties, который будет использоваться для настройки свойств каждого пункта меню. Мы можем установить размер шрифта, цвет метки, цвет фона и значение альфа для каждого пункта с использованием этого класса.
class ItemProperties:
def __init__(self, fontsize=14, labelcolor='black', bgcolor='yellow',
alpha=1.0):
self.fontsize = fontsize
self.labelcolor = labelcolor
self.bgcolor = bgcolor
self.alpha = alpha
Определение класса MenuItem
Теперь мы определяем класс MenuItem, который будет использоваться для создания каждого пункта меню. Мы передаем фигуру, строку с меткой, свойства, свойства при наведении курсора и функцию обратного вызова при выборе в качестве параметров этому классу. Класс MenuItem наследуется от класса artist.Artist.
class MenuItem(artist.Artist):
padx = 5
pady = 5
def __init__(self, fig, labelstr, props=None, hoverprops=None,
on_select=None):
super().__init__()
self.set_figure(fig)
self.labelstr = labelstr
self.props = props if props is not None else ItemProperties()
self.hoverprops = (
hoverprops if hoverprops is not None else ItemProperties())
if self.props.fontsize!= self.hoverprops.fontsize:
raise NotImplementedError(
'support for different font sizes not implemented')
self.on_select = on_select
## Setting the transform to IdentityTransform() lets us specify
## coordinates directly in pixels.
self.label = fig.text(0, 0, labelstr, transform=IdentityTransform(),
size=props.fontsize)
self.text_bbox = self.label.get_window_extent(
fig.canvas.get_renderer())
self.rect = patches.Rectangle((0, 0), 1, 1) ## Will be updated later.
self.set_hover_props(False)
fig.canvas.mpl_connect('button_release_event', self.check_select)
def check_select(self, event):
over, _ = self.rect.contains(event)
if not over:
return
if self.on_select is not None:
self.on_select(self)
def set_extent(self, x, y, w, h, depth):
self.rect.set(x=x, y=y, width=w, height=h)
self.label.set(position=(x + self.padx, y + depth + self.pady/2))
self.hover = False
def draw(self, renderer):
self.rect.draw(renderer)
self.label.draw(renderer)
def set_hover_props(self, b):
props = self.hoverprops if b else self.props
self.label.set(color=props.labelcolor)
self.rect.set(facecolor=props.bgcolor, alpha=props.alpha)
def set_hover(self, event):
"""
Update the hover status of event and return whether it was changed.
"""
b, _ = self.rect.contains(event)
changed = (b!= self.hover)
if changed:
self.set_hover_props(b)
self.hover = b
return changed
Определение класса Menu
Нам также нужно определить класс Menu, который будет использоваться для создания меню. Мы передаем фигуру и список элементов меню в качестве параметров этому классу.
class Menu:
def __init__(self, fig, menuitems):
self.figure = fig
self.menuitems = menuitems
maxw = max(item.text_bbox.width for item in menuitems)
maxh = max(item.text_bbox.height for item in menuitems)
depth = max(-item.text_bbox.y0 for item in menuitems)
x0 = 100
y0 = 400
width = maxw + 2*MenuItem.padx
height = maxh + MenuItem.pady
for item in menuitems:
left = x0
bottom = y0 - maxh - MenuItem.pady
item.set_extent(left, bottom, width, height, depth)
fig.artists.append(item)
y0 -= maxh + MenuItem.pady
fig.canvas.mpl_connect('motion_notify_event', self.on_move)
def on_move(self, event):
if any(item.set_hover(event) for item in self.menuitems):
self.figure.canvas.draw()
Создание меню
Теперь мы можем создать меню. Мы создаем новую фигуру и настраиваем левый отступ. Затем мы создаем список элементов меню и добавляем их в меню. Мы также определяем функцию обратного вызова для каждого элемента, которая будет выводить выбранный элемент.
fig = plt.figure()
fig.subplots_adjust(left=0.3)
props = ItemProperties(labelcolor='black', bgcolor='yellow',
fontsize=15, alpha=0.2)
hoverprops = ItemProperties(labelcolor='white', bgcolor='blue',
fontsize=15, alpha=0.2)
menuitems = []
for label in ('open', 'close','save','save as', 'quit'):
def on_select(item):
print('you selected %s' % item.labelstr)
item = MenuItem(fig, label, props=props, hoverprops=hoverprops,
on_select=on_select)
menuitems.append(item)
menu = Menu(fig, menuitems)
plt.show()
Резюме
Поздравляем! Вы успешно создали простое меню с использованием Matplotlib. Вы узнали, как создать класс MenuItem, класс Menu и как определить свойства для каждого элемента. Вы также узнали, как создать функцию обратного вызова для каждого элемента, которая будет выполнять какое-то действие.