Графическое представление виджетов отображается с помощью холста, который вы можете видеть как неограниченную чертежную доску, так и набор инструкций по рисованию. Существует множество инструкций, которые вы можете применить (добавить) к своему холсту, но есть два основных варианта:
- context instructions
- vertex instructions
Контекстные инструкции ничего не рисуют, но они изменяют результаты вершинных инструкций
Canvasses могут содержать два подмножества инструкций. Это canvas.before
и canvas.after
группы инструкций. Инструкции в этих группах будут выполняться до и после группы canvas соответственно. Это означает, что они появятся под (будут выполнены до) и выше (будут выполнены после) их. Эти группы не создаются, пока пользователь не обращается к ним.
Контекстные инструкции управляют контекстом opengl. Вы можете вращать, переводить и масштабировать холст. Вы также можете прикрепить текстуру или изменить цвет рисунка. Это один из наиболее часто используемых, но другие действительно полезны тоже:
with self.canvas.before: Color(1, 0, .4, mode='rgb') Rectangle(size=(50, 50))
Либо то же самое без использования with
:
self.canvas.add(Color(1., 1., 0)) self.canvas.add(Rectangle(size=(50, 50)))
Иногда требуется обновить или удалить инструкции, добавленные на холст. Это может быть сделано различными способами в зависимости от ваших потребностей:
Вы можете сохранить ссылку на ваши инструкции и обновить их:
class MyWidget(Widget): def __init__(self, **kwargs): super(MyWidget, self).__init__(**kwargs) with self.canvas: self.rect = Rectangle(pos=self.pos, size=self.size) self.bind(pos=self.update_rect) self.bind(size=self.update_rect) def update_rect(self, *args): self.rect.pos = self.pos self.rect.size = self.size
Или вы можете очистить свой холст и начать все заново:
class MyWidget(Widget): def __init__(self, **kwargs): super(MyWidget, self).__init__(**kwargs) self.draw_my_stuff() self.bind(pos=self.draw_my_stuff) self.bind(size=self.draw_my_stuff) def draw_my_stuff(self): self.canvas.clear() with self.canvas: self.rect = Rectangle(pos=self.pos, size=self.size)
Обратите внимание, что обновление инструкций считается лучшей практикой, поскольку она включает в себя меньше накладных расходов и позволяет избежать создания новых инструкций.
Что еще полезно знать?
Drawing after the children with canvas.after
Что произойдет, если мы хотим выполнить инструкции после добавления дочерних элементов. В этом случае у нас есть еще один холст (называется canvas.after
), что выполняется после прохождения всех дочерних элементов. Например:
Widget: canvas: ... canvas.after: ... Button: canvas.before: ... canvas: ... canvas.after: ...
В примере выше canvas
будет выполняться в следующей последовательности:
(1) The Widget
canvas
(2) All the Button
canvas
(canvas.before
, canvas
, canvas.after
)
(3) The Widget
canvas.after
Замечу, что все холсты Button будут выполнены между canvas
и canvas.before
Что насчет canvas.before
?
Вы, наверное, заметили, что есть и третий холст (canvas.before) Он выполняется непосредственно перед canvas. Я нашел canvas.before особенно полезно, когда (1) мне нужно манипулировать цветом экземпляра и (2) мне нужно манипулировать наследованием. Допустим, у меня есть виджет, который рисует прямоугольник внутри.
<MyWidget@Widget>: canvas: Rectangle: ...
Поэтому я могу изменить цвет конкретного экземпляра, делая что-то вроде этого:
... mywidget = MyWidget mywidget.canvas.before: Color(rgba=(1,0,0,0))
If I use canvas instead of canvas.before in RedWidget, the instruction is going to be executed after the Rectangle, so it won’t apply to the Rectangle.
Если я использую canvas вместо canvas.before в RedWidget, инструкция будет выполнена после Rectangle, и не будет применена к нему.
(2) точно так же, когда мне нужно манипулировать наследованием. Допустим, у меня есть виджет, который рисует прямоугольник внутри. Я могу сделать следующее, чтобы изменить цвет прямоугольника базового класса:
<RedWidget@MyWidget>: canvas.before: Color: rgb: 1,0,0
RedWidget наследует от моего MyWidget, и у меня будет такая же проблема, если я просто использую canvas. Поэтому следует использовать canvas.before.
Подробнее тут.
от