”;
The Kivy framework is equipped with powerful graphics capabilities built on top of OpenGL and SDL instructions. Kivy, like many of the graphics toolkits, provides a canvas to render graphics. However, Kivy”s canvas is different from Canvas object found in other frameworks, for example the Canvas in HTML5, or even the Canvas in Python”s TKinter library. Let us try to understand how using graphics in Kivy is different.
In Kivy a Graphics Canvas is a set of drawing instructions that define the graphical representation of a widget, which you can see as an unlimited drawing board. Although each GUI widget in Kivy library has a Canvas, all the Kivy widgets share the same coordinate space, which is where you can draw. The coordinate space is not restricted to the size of the window or the application window, so that we can even draw outside of the visible area.
There are two types of graphic instructions in Kivy −
-
Vertex instructions − Instructions used to draw basic geometric shapes like lines, rectangles, ellipses etc. are called vertex instructions.
-
Context instructions − These instructions don”t draw anything but manipulate the whole coordinate space, so to add colors to it, rotate, translate and scale it.
The effect of a certain context instruction on a canvas object − for example if we apply rotate instruction to a button”s canvas − will be visible in all the subsequent graphics instructions because all widgets share in the coordinate space.
Vertex Instructions
OpenGL uses vertices to describe its graphic objects. Vertex instructions are instructions that draw graphics. Common vertex instructions include Point, Line, Triangle, Rectangle, Ellipse, Mesh, Bezier, etc. The chapter Kivy – Drawing explains the use of drawing instructions in detail.
Context Instructions
Kivy”s Graphics instructions include Rotate, Translate, and Scale instructions. They are context instructions that are applied to the vertex instructions, which are displayed in the coordinate space
Rotate
The Rotate instruction works in the context of an object”s canvas. The object is rotated in given angle and along given axis.
with self.canvas: rotate = Rotate(angle=45)
The rotation is performed as per the parameters passed to it.
-
angle − Property for getting/setting the angle of the rotation. Ranes between 0 to 360
-
axis − Property for getting/setting the axis of the rotation. The format of axis is (x, y, z).
-
origin − Origin of the rotation. The format of the origin can be either (x, y) or (x, y, z).
-
set(float angle, float ax, float ay, float az) − This function sets the angle and axis of rotation.
Scale
The Scale instruction works in the context of an object”s canvas. It changes the size of the object along the given axes as per the scale ratio.
with self.canvas: s=Scale(2,2,1)
A Scale instruction Create using one or three arguments −
Scale(x, y, z)
Following parameters are accepted by Scale instruction −
origin − Origin of the scale. The format of the origin can be either (x, y) or (x, y, z).
-
x − Property for getting/setting the scale on the X axis.
-
y − Property for getting/setting the scale on the Y axis.
-
z − Property for getting/setting the scale on Z axis.
-
xyz − 3 tuple scale vector in 3D in x, y, and z axis.
The scaling and rotation instructions under the canvas of a particular object causes the entire canvas to change because the canvases share the same coordinate space. Therefore, to retrieve the position and state of the other widgets, there are PushMatrix and PopMatrix instructions.
-
PushMatrix saves the current coordinate space context and.
-
PopMatrix retrieves the last saved coordinate space context.
Therefore, the transformation instructions (Scale, Rotate, and Translate) surrounded by PushMatrix and PopMatrix won”t affect the rest of the interface.
Example
We start with placing a label and two buttons on the app window. We use a FloatLAyout that gives us a freedom to place the widgets at the specific coordinates and of specified size.
The Label is provided with a background color by drawing a colored rectangle on its canvas −
self.lbl = Label( text= ''Hello World'', font_size=24, halign=''center'',size_hint=(.2, .1), pos=(300, 250) ) with self.lbl.canvas: Color(0, 1, 0, 0.25) Rectangle(pos=self.lbl.pos, size=(200,50))
The button caption Rotate is bound to the update_rotate() method that applies a 45 degree rotation. Note that the PushMatrix stores the coordinates space before rotation and PopMatrix is called after the rotation.
def update_rotate(self, instance): with self.lbl.canvas.before: PushMatrix() rotate = Rotate(angle=45) with self.lbl.canvas.after: PopMatrix() rotate.origin = self.lbl.center
The Scale button when pressed, causes the Rotate button to be scaled along the X and Y axis. The update_scale() method for the purpose is as below −
def update_scale(self, instance): with self.btn.canvas.before: PushMatrix() s = Scale(2, 2, 1) with self.btn.canvas.after: PopMatrix() s.origin = self.btn.center
The complete example code is as follows −
from kivy.app import App from kivy.graphics import * from kivy.uix.floatlayout import FloatLayout from kivy.uix.button import Button from kivy.uix.label import Label from kivy.core.window import Window Window.size = (720, 400) class RotationApp(App): def update_rotate(self, instance): with self.lbl.canvas.before: PushMatrix() rotate = Rotate(angle=45) with self.lbl.canvas.after: PopMatrix() rotate.origin = self.lbl.center def update_scale(self, instance): with self.btn.canvas.before: PushMatrix() s = Scale(2, 2, 1) with self.btn.canvas.after: PopMatrix() s.origin = self.btn.center def build(self): root = FloatLayout() self.lbl = Label( text=''Hello World'', font_size=24, halign=''center'', size_hint=(.2, .1), pos=(300, 250) ) with self.lbl.canvas: Color(0, 1, 0, 0.25) Rectangle(pos=self.lbl.pos, size=(200, 50)) self.btn = Button( text=''Rotate'', size_hint=(None, None), pos_hint={''center_x'': .3, ''center_y'': .1} ) root.add_widget(self.lbl) self.btn1 = Button( text=''Scale'', size_hint=(None, None), pos_hint={''center_x'': .6, ''center_y'': .1} ) self.btn.bind(on_press=self.update_rotate) self.btn1.bind(on_press=self.update_scale) root.add_widget(self.btn) root.add_widget(self.btn1) return root RotationApp().run()
Output
Run the above code. When you click the “Rotate” button, the label “Hello World” will rotate by 45 degrees.
Click the Scale button. It will change the dimension of Rotate button along the X and Y axes.
”;