Kivy – Graphics ”; Previous Next 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”
Category: kivy
Kivy – Label
Kivy – Label ”; Previous Next Labels are one of the most often used widgets in any GUI toolkit. Labels display any textual content, which can not be directly edited. A label is used to display the page heading, as a placeholder for the field name along with the input controls like text box, or just to render output message. In Kivy, the label widget is an object of Label class, defined in the “kivy.uix.label” module. from kivy.uix.Label import Label lbl = Label(**kwargs) To customize the label object, you can use the following properties as keyword arguments for the constructor − bold − bold is a BooleanProperty and defaults to False. Set it to True for the use of the bold version of your font. Note that depending of your font, the bold attribute may have no impact on your text rendering. color − Text color, in the format (r, g, b, a). It is a ColorProperty, defaults to [1, 1, 1, 1]. disabled_color − The color of the text when the label is disabled, in the (r, g, b, a) format. It is a ColorProperty and defaults to [1, 1, 1, .3]. font_name − Filename of the font to use. font_name is a StringProperty and defaults to ”Roboto”. This value is taken from Config. font_size − Font size of the text, in pixels. It is a NumericProperty and defaults to 15sp. halign − Horizontal alignment of the text. halign is an OptionProperty and defaults to ”auto”. Available options are : auto, left, center, right and justify. italic − Indicates use of the italic version of your font. italic is a BooleanProperty and defaults to False. markup − If True, the text will be rendered using the MarkupLabel: you can change the style of the text using tags. outline_color − The color of the text outline, in the (r, g, b) format. It is a ColorProperty and defaults to [0, 0, 0, 1] padding − Padding of the text in the format [padding_left, padding_top, padding_right, padding_bottom]. padding also accepts a two argument form [padding_horizontal, padding_vertical] and a one argument form [padding]. strikethrough − Adds a strikethrough line to the text. strikethrough is a BooleanProperty and defaults to False. text − Text of the label caption. text is a StringProperty and defaults to ””. For example − lbl = Label(text=”Hello world”) text_size − By default, the label is not constrained to any bounding box. You can set the size constraint of the label with this property. The text will autoflow into the constraints. So although the font size will not be reduced, the text will be arranged to fit into the box as best as possible, with any text still outside the box clipped. Label(text=”long text . . . ”, text_size=(200, None)) text_size is a ListProperty and defaults to (None, None), meaning no size restriction by default. texture − Texture object of the text. The text is rendered automatically when a property changes. The texture is an ObjectProperty and defaults to None. texture_size − Texture size of the text. The size is determined by the font size and text. If text_size is [None, None], the texture will be the size required to fit the text, otherwise it”s clipped to fit text_size. underline − Adds an underline to the text. underline is a BooleanProperty and defaults to False. valign − Vertical alignment of the text. It is an OptionProperty and defaults to ”bottom”. Available options are : ”bottom”, ”middle” (or ”center”) and ”top”. Alignment Although the Label class has halign and valign properties, the text image (texture) is only large enough so that characters are positioned in the center of the Label. The valign property will have no effect and halign will only have an effect if your text has newlines; a single line of text will appear to be centered even though halign is set to left (by default). For the alignment properties to be effective, set the text_size, which is the size of the bounding box within which text is aligned. For instance, the following code binds this size to the size of the Label, so text will be aligned within the widget bounds. Label: text_size: self.size halign: ”left” valign: ”middle” Markup If the markup property of Label is True, the text will be rendered using the Text markup, used for nline text styling. Just like html tags, the Text markup tags have [tag], and should have a corresponding [/tag] closing tag. For example − [b]Hello [color=ff0000]world[/color][/b] The following tags can be used to construct the label text − Sr.No Tags & Label Text Description 1 [b][/b] Activate bold text 2 [i][/i] Activate italic text 3 [u][/u] Underlined text 4 [s][/s] Strikethrough text 5 [font=<str>][/font] Change the font (note – this refers to a TTF file or registered alias) 6 [size=<size>][/size] Change the font size. should be an integer, optionally with a unit (i.e. 16sp) 7 [color=#<color>][/color] Change the text color 8 [sub][/sub] Display the text at a subscript position relative to the text before it. 9 [sup][/sup] Display the text at a superscript position relative to the text before it. For example, this creates a label hello world with world in bold l = Label(text=”Hello [b]World[/b]”, markup=True) Sizing The size of Label is not affected by text content and also the text is not affected by the size. In order to control sizing, you must specify text_size to constrain the text and/or
Kivy – Button Events
Kivy – Button Events ”; Previous Next A Button, as most of the GUI widgets in Kivy, is programmed to respond to specific types of events. A Button processes the following event types − on_press − Triggered when the button is pressed. on_release − Triggered when the button is released. on_touch_down − Triggered when a touch event starts on the button. on_touch_up − Triggered when a touch event ends on the button. Kivy”s EventDispatcher class provides a bind() method which is responsible for delegating the event to a certain callback function for processing. EventDispatcher.bind(self, **kwargs) Button (as does each Kivy widget) inherits this method. Hence, we can bind a Button object to any callback eventhandler function. You can also bind a property to a callback. Binding Event Given below is a typical way to bind the on_press event of a button is bound to a function − def callback(instance): print(”The button is being pressed”) btn1 = Button(text=”Hello world”) btn1.bind(on_press=callback) Example In the following example, we have put two buttons inside FloatLayout. The “on_press” event of each button is bound to the callback() method. The reference of the button on which the “on_press” event occurred is passed to the callback() method, so that we can identify the caption of the button pressed. from kivy.app import App from kivy.uix.button import Button from kivy.config import Config from kivy.uix.floatlayout import FloatLayout # Configuration Config.set(”graphics”, ”width”, ”720”) Config.set(”graphics”, ”height”, ”400”) Config.set(”graphics”, ”resizable”, ”1”) class ButtonApp(App): def on_button_press(self, instance): print(“{} Button pressed!”.format(instance.text)) def build(self): flo = FloatLayout() btn1 = Button(text= ”Hello World”, background_color= [1,0,0,1], font_size= 20, underline= True, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.8}) btn1.bind(on_press = self.on_button_press) btn2 = Button(text= ”Hello Python”, color= [0,0,1,1], font_size= 20, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.2}) flo.add_widget(btn1) btn2.bind(on_press = self.on_button_press) flo.add_widget(btn2) return flo if __name__ == ”__main__”: ButtonApp().run() Output Run the above code and press the buttons − On each press, the callback() method is invoked − Hello World Button pressed! Hello Python Button pressed! Binding Property As mentioned earlier, we can bind a callback to a property of a widget. Every time the value of the property changes, the callback is invoked to notify the change. btn1.bind(property=callback) Let us define another method “on_textchanged()” in the App class, and bind it with the text property of btn2. The on_press event on btn1 changes the caption of btn2, and the change invokes the on_textchanged() method immediately. Example Change the code for ButtonApp class as below − from kivy.app import App from kivy.uix.button import Button from kivy.config import Config from kivy.uix.floatlayout import FloatLayout # Configuration Config.set(”graphics”, ”width”, ”720”) Config.set(”graphics”, ”height”, ”400”) Config.set(”graphics”, ”resizable”, ”1”) class ButtonApp(App): def on_button_press(self, instance): print(“{} Button pressed!”.format(instance.text)) self.btn2.text=”Hello Tutorialspoint” def on_textchanged(self, instance, value): print (“Text property changed to”, instance.text) def build(self): flo = FloatLayout() self.btn1 = Button(text= ”Hello World”, background_color= [1,0,0,1], font_size= 20, underline= True, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.8}) self.btn1.bind(on_press = self.on_button_press) self.btn2 = Button(text= ”Hello Python”, color= [0,0,1,1], font_size= 20, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.2}) flo.add_widget(self.btn1) self.btn2.bind(text = self.on_textchanged) flo.add_widget(self.btn2) return flo if __name__ == ”__main__”: ButtonApp().run() Output Run the code and first press btn1. It changes the caption of btn2 and it in turn calls the “on_textchanged()” method. Hello World Button pressed! Text property changed to Hello Tutorialspoint Here”s the output window − In general, property callbacks are called with two arguments (the object and the property”s new value) and “event callbacks” with one argument (the object). Binding using Lambda Function Another approach for binding is to use lambda (or anonymous) function. Their advantage is that you can avoid declaring new functions i.e. they offer a concise way to “redirect” callbacks. Change the statement that binds the “on_press” event of btn1 to − self.btn1.bind(on_press = lambda btn1: self.on_button_press(btn1)) Using Partial Function In Python, a Partial function allows us to derive a function with x parameters to a function with fewer parameters and constant values set for the more limited function. It makes a function reusable. The partial() function is defined in functools module of Python”s standard library. Example We can bind an event to a partial method. In the example below, the Button objects bt1 and btn2 are passed. The function interchanges the text property of the two. from kivy.app import App from kivy.uix.button import Button from kivy.config import Config from kivy.uix.floatlayout import FloatLayout from functools import partial # Configuration Config.set(”graphics”, ”width”, ”720”) Config.set(”graphics”, ”height”, ”300”) Config.set(”graphics”, ”resizable”, ”1”) class ButtonApp(App): def on_textchanged(self, instance, value): print (“Text property changed to”, instance.text) def a_function(self, *args): args[0].text, args[1].text = args[1].text, args[0].text def build(self): flo = FloatLayout() self.btn1 = Button(text= ”Hello World”, background_color= [1,0,0,1], font_size= 20, underline= True, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.8}) self.btn2 = Button(text= ”Hello Python”, color= [0,0,1,1], font_size= 20, size_hint= (.4, .25), pos_hint= {”center_x”:.5, ”center_y”:.2}) flo.add_widget(self.btn1) self.btn1.bind(on_press = partial(self.a_function, self.btn1, self.btn2)) self.btn2.bind(text = self.on_textchanged) flo.add_widget(self.btn2) return flo if __name__ == ”__main__”: ButtonApp().run() Output Take a look at the following output window and observe how pressing the first button interchanges the text of the two buttons − Print Page Previous Next Advertisements ”;
Kivy – Properties
Kivy – Properties ”; Previous Next A Property is a special class in Kivy that allows you to define and manage attributes of a widget or object. Property class is defined in the “kivy.properties” module. You can track changes to these attributes and they allow you to bind callback functions to be executed when the property changes. Kivy”s property classes support the following features − Value Checking / Validation Whenever a new value is assigned to a property, it is checked against validation constraints, in order to prevent errors. For example, validation for an OptionProperty will make sure that the value is in a predefined list of possibilities. Validation for a NumericProperty will check that your value is a numeric type. Observer Pattern You can specify what should happen when a property”s value changes. You can bind your own function as a callback to changes of a Property. If, for example, you want a piece of code to be called when a widget”s pos property changes, you can bind a function to it. Better Memory Management The same instance of a property is shared across multiple widget instances. It may be noted that the Property objects are not the same as property() built-in function in Python. A property object has to be declared at class level, not in any method of the class. Each property by default provides an “on_<propertyname>” event that is called whenever the property”s state/value changes. Example Let us study the behavior of Property in Kivy with the following example. The App class has a NumericProperty attribute. The NumericProperty object (value) is bound to on_value_change() method. class NumPropApp(App): value = NumericProperty(0) def on_value_change(self, instance, value): print(f”Value changed: {value}”) self.l1.text = str(value) In the build() method, the app has a Label and a Button assembled in a vertical BoxLayout. The Button invokes onstart() method in response to on_press event and increments value with 1. def onstart(self, event): print (“started”) self.value = self.value+1 def build(self): lo = BoxLayout(orientation=”vertical”) self.l1 = Label(text=str(self.value), font_size = 50) self.b1 = Button(text = “start”, font_size = 50) self.b1.bind(on_press=self.onstart) self.bind(value=self.on_value_change) lo.add_widget(self.l1) lo.add_widget(self.b1) return lo Since the “on_value_change()” method is invoked on every change in value, the effect is that on every button press, the label caption shows increasing number from “0” onwards. Here is the complete code of the example − from kivy.app import App from kivy.uix.label import Label from kivy.uix.button import Button from kivy.properties import NumericProperty from kivy.uix.boxlayout import BoxLayout from kivy.config import Config # Configuration Config.set(”graphics”, ”width”, ”720”) Config.set(”graphics”, ”height”, ”400”) Config.set(”graphics”, ”resizable”, ”1”) class NumPropApp(App): value = NumericProperty(0) def on_value_change(self, instance, value): print(f”Value changed: {value}”) self.l1.text = str(value) def onstart(self, event): print (“started”) self.value = self.value+1 def build(self): lo = BoxLayout(orientation=”vertical”) self.l1 = Label(text=str(self.value), font_size = 50) self.b1 = Button(text = “start”, font_size = 50) self.b1.bind(on_press=self.onstart) self.bind(value=self.on_value_change) lo.add_widget(self.l1) lo.add_widget(self.b1) return lo if __name__ == ”__main__”: NumPropApp().run() Output Run the program from the command line. Press the button to see that every time the number displayed on the label increases. Property Types Kivy provides the following Property types − NumericProperty − Handles numeric values such as integers and floats. It only accepts the int or float numeric data type or a string that can be converted to a number. count = NumericProperty(0) StringProperty − It is used to handle string values. You can initialize it with “defaultvalue” parameter. text = StringProperty(“start”) BoundedNumericProperty − This property is Similar to NumericProperty, but allows you to define minimum and maximum bounds for the value. It also supports get_min() and get_max() methods that return minimum and maximum acceptable values respectively. a = BoundedNumericProperty(1, min=0, max=100) BooleanProperty − Handles boolean values (True or False). The defaultvalue parameter can be set to True or False. active = BooleanProperty(False) ListProperty − The value of this property is a List object. When assigning a list to a ListProperty, the list stored in the property is a shallow copy of the list and not the original list. colors = ListProperty([1, 0, 0, 1]) ObjectProperty − Handles a single object instance. If the rebind parameter is set to True, the associated kv rule will be re-evaluated and all the properties will be rebound when any intermediate property changes. person = ObjectProperty(None) OptionProperty − Specifies the default value of the property. It should be one from the list given in Options parameter. Example − state = OptionProperty(“None”, options=[“On”, “Off”, “None”]) ReferenceListProperty − This property is used to refer to one or more property objects of other types. x = NumericProperty(0) y = NumericProperty(0) z = ReferenceListProperty(x, y) Changing the value of “z” will automatically change the values of “x” and “y” accordingly. If you read the value of “z”, it will return a tuple with the values of “x” and “y”. AliasProperty − Provides an alias or alternative name for an existing property. def _get_width(self): return self.size def _set_width(self, value): self.size = value width = AliasProperty(_get_width, _set_width) DictProperty − Used to define the initial value of an object with multiple parameters as the dictionary keys. params = DictProperty({ ”xlog”: False, ”xmin”: 0, ”xmax”: 100, ”ylog”: False, ”ymin”: 0, ”ymax”: 100, ”size”: (0, 0, 0, 0) }) VariableListProperty − list items and to expand them to the desired list size. obj = VariableListProperty(defaultvalue, length) The defaultvalue parameter specifies the default values for the list. The length parameter is an int, either 2 or 4. ConfigParserProperty − ConfigParserProperty lets you automatically listen to and change the values of specified keys based on other kivy properties. ConfigParserProperty(defaultvalue, section, key, config) A ConfigParser is composed of sections, where each
Kivy – ScrollView
Kivy – ScrollView ”; Previous Next The ScrollView widget in Kivy framework encloses any other widget having dimensions larger than the size allocated to it, and provides a scrollable panel to it. This enables the enclosed widget to be panned/scrolled vertically or horizontally. The ScrollView class is defined in kivy.uix.scrollview module. You normally compose one or more widgets in a layout and add the layout to the ScrollView. from kivy.uix.scrollview import ScrollView view = ScrollView() view.add_widget(layout) The “scroll_x” and “scroll_y” properties of a ScrollView object control the scrolling behavior of the scroll panel. The ScollView enables scrolling in both directions. You can disable on an axis by setting “do_scroll_x” or “do_scroll_y” to False. Further, the “scroll_distance” property sets the minimum distance to travel, defaults to 20 pixels. Additionally, the scroll_timeout property specifies the maximum time period which is by default 55 milliseconds. The significance of “scroll_distance” and “scroll_timeout” is this: If the number of pixels scrolled by the touch gesture is more than or equal to scroll_distance, and it is within the scroll_timeout period, it is recognized as a scrolling gesture and translation (scroll/pan) will begin. If the timeout occurs, the touch down event is propagated to the child instead. Other properties of ScrollView class are given below − do_scroll − Allow scroll on X or Y axis. do_scroll_x − Allow scroll on X axis. This is a BooleanProperty and defaults to True. do_scroll_y − Allow scroll on Y axis. This is a BooleanProperty and defaults to True. scroll_distance − Distance to move before scrolling the ScrollView, in pixels. It is a NumericProperty and defaults to 20 pixels. scroll_timeout − Timeout allowed to trigger the scroll_distance, in milliseconds, default being 55 ms scroll_to() − Scrolls the viewport to ensure that the given widget is visible, optionally with padding and animation. scroll_type − Sets the type of scrolling to use for the content of the scrollview. Available options are: [”content”], [”bars”], [”bars”, ”content”]. The ScrollView object emits following events − on_scroll_start − Generic event fired when scrolling starts from touch. on_scroll_move − Generic event fired when scrolling move from touch. on_scroll_stop − Generic event fired when scrolling stops from touch. Example To be able to understand the working of ScrollView, we need a layout large enough, so that it overflows the dimensions of the main application window. For this purpose, we add 1oo buttons to a one-column gridlayout, and apply scrollview to it. The operative code in the following example is given below − layout = GridLayout(cols=1) for i in range(100): btn = Button(text=”Button ” + str(i), size_hint_y=None, height=40) layout.add_widget(btn) root = ScrollView() root.add_widget(layout) To make sure the height is such that there is something to scroll, bind the layout object”s minimum_height property to its setter. layout.bind(minimum_height=layout.setter(”height”)) Here is the complete code for ScrollView demo code − from kivy.uix.gridlayout import GridLayout from kivy.uix.button import Button from kivy.uix.scrollview import ScrollView from kivy.app import App from kivy.core.window import Window Window.size = (720, 350) class scrollableapp(App): def build(self): layout = GridLayout(cols=1, spacing=10, size_hint_y=None) layout.bind(minimum_height=layout.setter(”height”)) for i in range(100): btn = Button(text=”Button ” + str(i), size_hint_y=None, height=40) layout.add_widget(btn) root = ScrollView( size_hint=(1, None), size=(Window.width, Window.height) ) root.add_widget(layout) return root scrollableapp().run() Output Run the above code. To go beyond the buttons visible in the view, scroll vertically with mouse, or fingers if you are working on a touch-enabled device. Print Page Previous Next Advertisements ”;
Kivy – Gesture
Kivy – Gesture ”; Previous Next The Kivy framework is capable of recording and identifying the gestures. Gesture is a sequence of touches generated by mouse pointer or fingers on a multitouch device. The kivy.gesture module defines Gesture class whose object is obtained by the (x,y) coordinated of the successive touch events captured on Kivy canvas. Gesture in Kicy is a python implementation of a gesture recognition algorithm by Oleg Dopertchouk. The same module also has GestureDatabase class. You can store one more Gesture objects in the gesture database, and find out if a certain gesture matches with any of the gestures already stored in the database. To create a Gesture object, you need a list of x,y coordinates. For example − from kivy.gesture import Gesture g = Gesture() g.add_stroke(point_list=[(1,1), (3,4), (2,1)]) g.normalize() The add_stroke() method constructs a gesture object from the pairs of coordinates. The normalize() method is needed to run the gesture normalization algorithm and calculates the dot product with self. Such Gesture objects are stored in GestureDatabase. from kivy.gesture import Gesture, GestureDatabase # Create a gesture gdb = GestureDatabase() gdb.add_gesture(g) Against the objects stored in this database, you can compare a certain other object and find if any of the gestures in the database match. g2 = Gesture() # … gdb.find(g2) The kivy.gesture module defines following methods in Gesture class − add_stroke() − constructs a stroke from a list of touch points to the gesture and returns the Stroke instance. normalize() − Runs the gesture normalization algorithm and calculates the dot product with self. get_score() − When a gesture is matched with another, this method returns the matching score. The GestureDatabase class has following important methods − add_gesture() − Add a new gesture to the database. find() − Find a matching gesture in the database. You can define the precision of find with min_score parameter. It should be between 0 to 1. gesture_to_str(gesture) − Convert a gesture into a unique string. str_to_gesture(data) − Convert a unique string to a gesture. Example We define the touch_down(), touch_move() and touch_up() handlers to capture the touch points and draw a pattern from them. All the points with their (touch.x and touch.y) coordinates are collected in a List. When the Add button is pressed, the points List is used to construct a Gesture. The gesture_to_string() method returns a binary string. if instance.text==”Add”: g = Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() print (self.d.gdb.gesture_to_str(g)) self.d.gdb.add_gesture(g) print (str(g)) An example of the gesture string might look like this − b”eNprYJmayc4ABj082ZlllXrpqcUlpUWpU3rY3aGsyVM0G6fUTtHoYS3PTCnJmOLuYO9kuU766IwetozUzPSMEqCIC9NEhiUOGj38UO3xBUX5KaXJICmhWZ/F3Pse9LAXlxTlZ6cWT4mdksHQwws1PRgsiLCDrSA/M68EpEgDqIoHqioAJIhQxFgxxX3/LdkuHrnEhh7Gyinu9g9vmvlOTnlRmpQhCFGTIQJXkSHqbn9/U85stZMXcMrfxiZ/TfZI/b2QH8TIXydH/pLsv8/zPDJA8pfJkT9jU3RuT/kBYuTPp4ACaAGq/AmbtU412Qo45Q/YKmn+CRIAyR+nUP4wWD4BVX5DtZ7Sj8IHIPltJ4EeUHdAlY9n/VPH/4ABJL92MtAAvwaS5O3n8Z6ZJZ8Gkt9fDLK/hwGn/CJQ8G1E078eZP5TB5D8RlDyunEAp/xOkPxNNPO3N3WGd3CD/Lf/AND4TTlo5u9vEingUAHLnwDLo4aP/eED54+4yH3AKX/8wNSAFu0JIPkzYHnU8Lc/fSDqzhELUPzuvwBynpkBqvz5AwqZLC4LQPJXwPKo4W9/8f6nX4s0iJK/hk3+6v0dbY9MNUDyNyiUvwNzf2oPT3FyUWpqHqKccHdIcNSwvsgQ4+5QGrZn4XqNnLYpyGJOuwTWtWijiultr197/w2qGNum2DXTs8FiE3XfGfUrYRcrubfWerXfa7DYQ+MFU2RfAsW2rZBcxQZWl2hoGfR1zXocYn2Lvq/Y+wosFmmjo1YijCq20vFeB9NNoFja3KvLS7NQxYJmuyy7qAkWu+iyfccpW6CY3YzNy3Qgen+6T3g5cQFQTGua0tKOVSCxJE9fZ2+FdKCY2OSJS55kgsUKA2Sqn59ydyh+15e/ePZLVLFb3fcWfV8JFpsJcrIuUOxYp++i4ExUsU1toIAGix0MPXe3bCJQbF6L9kKuF2CxlxEr+Gy/AMXK6jnnH8oAiSULRjfas4ajilnGReWf2Q0US6qpmC+nDhZLTAQGqhxQzK/y+bzKF6hiVuVhc6+uAIt1pvBcjG4EiqmVHJ1rmA4W25j2jEnpKQ4xoSKTOb3qKGJF/4BB8OI5SCyFMWdG8sbVOMRe5QrNdlmOKnYtq3HWArAdKZr5hVMq+ZHEUkuTEns4S/JzUosS85JTgTXUzpkgMKs0SQ8Ayq8zuw==” You can add as many gestures as you want. Then, draw a pattern on the canvas and try to find out if any of the gestures matches with this one. The find() method does this work when the Find button is pressed. if instance.text==”Find”: g=Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() g1=self.d.gdb.find(g, 0.65) print (g1) Here is the complete code for gesture recognition exercise − from kivy.app import App from kivy.graphics import * from kivy.uix.floatlayout import FloatLayout from kivy.gesture import Gesture, GestureDatabase from kivy.uix.button import Button from kivy.uix.widget import Widget from random import random from kivy.core.window import Window Window.size = (720, 400) class Drawgesture(Widget): points = [] def __init__(self, *args, **kwargs): super(Drawgesture, self).__init__() self.gdb = GestureDatabase() def on_touch_down(self, touch): with self.canvas: self.col = (random(), random(), random()) Color(self.col) touch.ud[“line”] = Line(points=(touch.x, touch.y), width=3) Drawgesture.points.append((touch.x, touch.y)) def on_touch_move(self, touch): with self.canvas: Color(self.col) touch.ud[“line”].points += (touch.x, touch.y) Drawgesture.points.append((touch.x, touch.y)) def on_touch_up(self, touch): print(”touch up”) class gestureApp(App): def pressed(self, instance): if instance.text == ”Add”: g = Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() print(self.d.gdb.gesture_to_str(g)) self.d.gdb.add_gesture(g) print(str(g)) if instance.text == ”Find”: g = Gesture() g.add_stroke(point_list=Drawgesture.points) g.normalize() g1 = self.d.gdb.find(g, 0.65) print(g1) if instance.text == ”Clear”: self.d.canvas.clear() def build(self): f = FloatLayout() self.d = Drawgesture() f.add_widget(self.d) b1 = Button( text=”Add”, pos_hint={”x”: 0, ”y”: 0}, size_hint=(None, None) ) f.add_widget(b1) b2 = Button( text=”Find”, pos_hint={”x”: .2, ”y”: 0}, size_hint=(None, None) ) f.add_widget(b2) b3 = Button( text=”Clear”, pos_hint={”x”: .4, ”y”: 0}, size_hint=(None, None) ) f.add_widget(b3) b1.bind(on_press=self.pressed) b2.bind(on_press=self.pressed) b3.bind(on_press=self.pressed) return f gestureApp().run() Output If the match store is greater than or equal to the min_score parameter, you get the following result − (0.7093289348205829, <kivy.gesture.Gesture object at 0x000001B817C70490>) Print Page Previous Next Advertisements ”;
Kivy – Framebuffer
Kivy – Framebuffer ”; Previous Next Kivy library provides an “Fbo” class which stands for Framebuffer offscreen. It is an off-screen window on which you can draw any graphics instructions and then use it as a texture for the canvas of a certain Kivy widget. The Fbo class is defined in kivy.graphics,fbo module. The first step is to create the fbo and use the fbo texture on other rectangle. from kivy.graphics import Fbo, Color, Rectangle with self.canvas: self.fbo = Fbo(size=self.size) Next, add graphics instructions such as Rectangle to the Fbo object. For example − with self.fbo: Color(1, 0, 0, .8) Rectangle(size=(256, 64)) Color(0, 1, 0, .8) Rectangle(size=(64, 256)) Finally, apply the Fbo texture to the canvas. self.texture = self.fbo.texture Note that the FBO is lost if the OpenGL context is lost. In such a case, you need to reupload data using the Fbo.add_reload_observer() method.. add_reload_observer(callback) − Add a callback to be called after the whole graphics context has been reloaded. The callback parameter will be the context itself. The bind() method binds the FBO object to the current opengl context. This way all the drawing operations will act inside the Framebuffer, until release() is called. The release() method releases or unbinds the Framebuffer. self.fbo = FBO() self.fbo.bind() # do any drawing command self.fbo.release() self.canvas = self.fbo.texture There is also a remove_reload_observer(callback) method that removes a callback from the observer list, previously added by add_reload_observer(). The clear_buffer() and clear_color methods clear the framebuffer and clear color in (red, green, blue, alpha) format. Example The following code demonstrates the use of Framebuffer in a Kivy application. The important part of the code is a class named as FboFloatLayout which inherits Kivy”s FloatLayout class. The constructor (__init__() method) creates a Fbo object on the canvase of float layout, draws a rectangle on it and sets its texture as the texture of the canvas. def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) self.fbo_color = Color(1, 1, 1, 1) self.fbo_rect = Rectangle() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs) we are going to add a button to this FloatLayout class, but before that the add_widget() method is overridden so as to add the graphics instruction to the fbo and then add it to the canvas. def add_widget(self, *args, **kwargs): canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*args, **kwargs) self.canvas = canvas return ret The FboFloatLayout class also has the callbacks that respond to the changes in the size, pos and texture. def on_size(self, instance, value): self.fbo.size = value self.texture = self.fbo.texture self.fbo_rect.size = value def on_pos(self, instance, value): self.fbo_rect.pos = value def on_texture(self, instance, value): self.fbo_rect.texture = value Now to the App class. The build() method adds a button and applies a series of animation effects that change the button position up to down and from right to left, repeatedly. def anim_btn(*args): animate = Animation(pos=(b.pos[0], Window.height – 50)) animate += Animation(pos=(b.pos[0], 0)) animate += Animation(pos_hint={”center_x”: 1}) animate += Animation(pos_hint={”center_x”: 0}) animate += Animation(pos_hint={”center_x”: .5}) animate.start(b) animate.repeat = True b.bind(on_press=anim_btn) These code fragments are put together in the complete code listing for the sake of convenience − from kivy.graphics import Color, Rectangle, Canvas, ClearBuffers, ClearColor from kivy.graphics.fbo import Fbo from kivy.uix.floatlayout import FloatLayout from kivy.uix.button import Button from kivy.properties import ObjectProperty, NumericProperty from kivy.app import App from kivy.animation import Animation from kivy.core.window import Window Window.size = (720, 400) class FboFloatLayout(FloatLayout): texture = ObjectProperty(None, allownone=True) def __init__(self, **kwargs): self.canvas = Canvas() with self.canvas: self.fbo = Fbo(size=self.size) self.fbo_color = Color(1, 1, 1, 1) self.fbo_rect = Rectangle() with self.fbo: ClearColor(0, 0, 0, 0) ClearBuffers() self.texture = self.fbo.texture super(FboFloatLayout, self).__init__(**kwargs) def add_widget(self, *args, **kwargs): canvas = self.canvas self.canvas = self.fbo ret = super(FboFloatLayout, self).add_widget(*args, **kwargs) self.canvas = canvas return ret def on_size(self, instance, value): self.fbo.size = value self.texture = self.fbo.texture self.fbo_rect.size = value def on_pos(self, instance, value): self.fbo_rect.pos = value def on_texture(self, instance, value): self.fbo_rect.texture = value class FBOdemoApp(App): def build(self): f = FboFloatLayout() b = Button(text=”FBO”, size_hint=(None, None), pos_hint={”center_x”: .5}) f.add_widget(b) def anim_btn(*args): animate = Animation(pos=(b.pos[0], Window.height – 50)) animate += Animation(pos=(b.pos[0], 0)) animate += Animation(pos_hint={”center_x”: 1}) animate += Animation(pos_hint={”center_x”: 0}) animate += Animation(pos_hint={”center_x”: .5}) animate.start(b) animate.repeat = True b.bind(on_press=anim_btn) return f FBOdemoApp().run() Output The application starts with a button captioned FBO at the bottom. When clicked, it starts its animation effects as defined. Print Page Previous Next Advertisements ”;
Kivy – Stopwatch App
Kivy – Stopwatch App ”; Previous Next In this chapter, we shall build a Stopwatch app using Python”s Kivy GUI framework. A stopwatch measures the time elapsed between the instances of starting an event and stopping it. For example, the stopwatch used to measure the time taken by an athlete to complete a 100-meter run. The GUI design for the app should resemble the following figure − The following “kv” script is used to place two labels and two buttons as shown in the above figure. The top label will be used to display the current time, and the label at the bottom will display the time elapsed after the timer is started. The left button is used to start/stop the stopwatch. The one on right resets the timer to 0. BoxLayout: orientation: ”vertical” Label: id: time font_size:40 markup:True text: ”[b]00[/b]:00:00” BoxLayout: orientation: ”horizontal” padding: 20 spacing: 20 height: 90 size_hint: (1, None) Button: text: ”Start” id: start_stop on_press : app.start_stop() Button: id: reset text: ”Reset” on_press: app.reset() Label: id: stopwatch font_size:40 markup:True text:”00:00.[size=40]00[/size]” In the application code, we define an on_stop() event handler that is invoke as soon as the GUI is populated. It schedules a time event handler which updates the label with current time after each second. def on_start(self): Clock.schedule_interval(self.update_time, 0) The update_time() method updates the current time displayed on the upper label (with id as time), and time elapsed on the lower label (with id as stopwatch) – if the timer has been started. def update_time(self, t): if self.sw_started: self.sw_seconds += t minutes, seconds = divmod(self.sw_seconds, 60) part_seconds = seconds * 100 % 100 self.root.ids.stopwatch.text = “{:2d} : {:2d}.{:2d}”.format(int(minutes), int(seconds), int(part_seconds)) self.root.ids.time.text = strftime(”[b]%H[/b]:%M:%S”) The Button with id=start is bound to start_stop() method which stores the status of the stopwatch whether it has started or stopped and accordingly updates the caption of the start button (with id as start_stop). def start_stop(self): self.root.ids.start_stop.text = ”Start” if self.sw_started else ”Stop” self.sw_started = not self.sw_started The button on right resets the time counter to 0, sets the caption of the other button to start and also resets the caption of the bottom label to 0:0.0. def reset(self): if self.sw_started: self.root.ids.start_stop.text = ”Start” self.sw_started = False self.sw_seconds = 0 Example The entire coding logic is gien in the code below − from time import strftime from kivy.clock import Clock from kivy.app import App from kivy.core.window import Window Window.size = (720, 400) class StopWatchApp(App): sw_seconds = 0 sw_started = False def update_time(self, t): if self.sw_started: self.sw_seconds += t minutes, seconds = divmod(self.sw_seconds, 60) part_seconds = seconds * 100 % 100 self.root.ids.stopwatch.text = “{:2d} : {:2d}.{:2d}”.format(int(minutes), int(seconds), int(part_seconds)) self.root.ids.time.text = strftime(”[b]%H[/b]:%M:%S”) def on_start(self): Clock.schedule_interval(self.update_time, 0) def start_stop(self): self.root.ids.start_stop.text = ”Start” if self.sw_started else ”Stop” self.sw_started = not self.sw_started def reset(self): if self.sw_started: self.root.ids.start_stop.text = ”Start” self.sw_started = False self.sw_seconds = 0 StopWatchApp().run() Output Since the name of the App class in the above code is StopWatchApp, its “kv” language design script must be named as “StopWatch.kv” and run the program. Press the Start button. The counter will start, showing the time elapsed on the bottom label. The caption changes to Stop. Press it again to stop the clock from running. Clicking the Reset button brings the label to “0”. Print Page Previous Next Advertisements ”;
Kivy – Modal View
Kivy – Modal View ”; Previous Next The ModalView widget in the Kivy framework is used to pop up a dialog box on top of the parent window. The behaviour of ModalView widget is similar to Kivy”s Popup widget. In fact, the Popup class itself is a subclass of ModalView class, with a certain additional functionality, such as having a title and a separator. By default, the size of Modalview is equal to that of “main” window. A widget”s size_hint=(1, 1) by default. If you don”t want your view to be fullscreen, either use size hints with values lower than 1 (for instance size_hint=(.8, .8)) or set the size_hint to None and use fixed size attributes. The ModalView class is defined in kivy.uix.modalview import ModalView module. The following statements will produce a ModalView dialog − from kivy.uix.modalview import ModalView view = ModalView(size_hint=(None, None), size=(300, 200)) view.add_widget(Label(text=”ModalView Dialog”)) As in case of a Popup, the ModalView dialog is dismissed as you click outside it. To prevent this behavior, set auto-dismiss to False. To make the ModalView dialog appear, you need to call its open() method. view.open() If auto_dismiss is False, you need to call its dismiss() method to close it. view.dismiss() Normally, both the open() and dismiss() method are invoked on a certain event such as on_press event of a button. You generally open a ModalView when a button on parent window is clicked, and dismissed when a buuton in ModalView layout is clicked. ModalView Events The ModalView emits events, before view is opened and dismissed, as well as when a view is opened and closed. on_pre_open − Fired before the ModalView is opened. When this event is fired ModalView is not yet added to window. on_open − Fired when the ModalView is opened. on_pre_dismiss − Fired before the ModalView is closed. on_dismiss − Fired when the ModalView is closed. If the callback returns True, the dismiss will be canceled. Example The following code presents an easy to implement example of ModalView dialog. The main application window displays a button caption as Click here. When clicked, a modal dialog pops up. The ModalView is constructed by putting a label and a button inside a gridlayout. On the popup, we have a button with Ok as its caption. Its on_press event is bound to the dismiss() method of the ModalView object, causing it to disappear. The complete code for the example is given below − from kivy.app import App from kivy.uix.label import Label from kivy.uix.button import Button from kivy.uix.modalview import ModalView from kivy.uix.floatlayout import FloatLayout from kivy.uix.gridlayout import GridLayout from kivy.core.window import Window Window.size = (720, 300) class ModalViewDemoApp(App): def showmodal(self, obj): view = ModalView( auto_dismiss=False, size_hint=(None, None), size=(400, 100) ) grid = GridLayout(cols=1, padding=10) grid.add_widget(Label( text=”ModalView Popup”, font_size=32, color=[1, 0, 0, 1] )) btn = Button( text=”ok”, font_size=32, on_press=view.dismiss ) grid.add_widget(btn) view.add_widget(grid) view.open() def build(self): btn = Button( text=”click here”, font_size=32, on_press=self.showmodal, pos_hint={”center_x”: .5, ”center_y”: .1}, size_hint=(.3, None), size=(200, 100) ) return btn ModalViewDemoApp().run() Output The ModalView dialog will pop up when the button on the main app window is clicked. Print Page Previous Next Advertisements ”;
Kivy – Circle Drawing
Kivy – Circle Drawing ”; Previous Next In this chapter, we shall dynamically draw a circle on a Kivy application window. The idea is to set the value of width, height, and the center point of circle with four Kivy slider widgets and refresh the size and the position on a box layout canvas. The “kivy.graphics” module includes the Ellipse class. A circle is actually an ellipse with equal width and height. Syntax The syntax to draw an ellipse on the canvas of any widget is − with widget.canvas: Color(1, 1, 1) Ellipse( pos=(w, h), size=(cx, cy), angle_start=0, angle_end=360 ) Sliders are to be used to select the values of “w”, “h”, “cx” and “cy”. The intended appearance of our application window is as follows − The main layout uses a vertical box layout. It includes two horizontal box, each housing two sliders and two labels. In the first, width and height selectors are placed; and in the second, X and Y coordinates of the ellipse can be selected. The top vertical box then adds a FloatLayout, whose canvas is the target for drawing. The following “kv” file assembles the above widget structure. Example BoxLayout: orientation: ”vertical” BoxLayout: size_hint_y: None height: sp(50) BoxLayout: orientation: ”horizontal” Slider: id: wd min: 100 max: 300 value: 200 Label: text: ”Width: {}”.format(int(wd.value)) Slider: id: ht min: 100 max: 300 value: 200 Label: text: ”Height: {}”.format(int(ht.value)) BoxLayout: size_hint_y: None height: sp(50) BoxLayout: orientation: ”horizontal” Slider: id: cx min: 10 max: 600 value: 360 Label: text: ”cx: {}”.format(int(cx.value)) Slider: id: cy min: 10 max: 300 value: 50 Label: text: ”cy: {}”.format(int(cy.value)) FloatLayout: canvas: Color: rgb: 1, 1, 1 Ellipse: pos: cx.value, cy.value size: wd.value, ht.value angle_start: 0 angle_end: 360 All you need to do is load this “kv” file in our Kivy App code. Call the load_file() method of “kivy.lang.Builder” class inside the build() method. from kivy.app import App from kivy.lang import Builder from kivy.core.window import Window Window.size = (720,400) class CircleApp(App): def build(self): return Builder.load_file(”circledemo.kv”) CircleApp().run() That”s it. Run the program, and you will get the circle drawn at the starting position. Slide the controls for different values and see the circle changing its position and size. If you wish to use pure Python code to compose the application window appearance, you can do so by manually placing the required widgets inside the build() method as follows − def build(self): # main layout lo = BoxLayout(orientation=”vertical”, size=Window.size) # for width and height sliders sliders_wh = BoxLayout(size_hint_y=None, height=50) slb1 = BoxLayout(orientation=”horizontal”) self.sl1 = Slider(min=100, max=300, value=200) l1 = Label(text=”Width: {}”.format(int(self.sl1.value))) slb1.add_widget(self.sl1) slb1.add_widget(l1) self.sl2 = Slider(min=100, max=300, value=200) l2 = Label(text=”Height: {}”.format(int(self.sl2.value))) slb1.add_widget(self.sl2) slb1.add_widget(l2) sliders_wh.add_widget(slb1) # for cx and cy sliders sliders_xy = BoxLayout(size_hint_y=None, height=50) slb2 = BoxLayout(orientation=”horizontal”) self.sl3 = Slider(min=10, max=600, value=360) l3 = Label(text=”cx: {}”.format(int(self.sl3.value))) slb2.add_widget(self.sl3) slb2.add_widget(l3) self.sl4 = Slider(min=10, max=300, value=50) l4 = Label(text=”cy: {}”.format(int(self.sl4.value))) slb2.add_widget(self.sl4) slb2.add_widget(l4) sliders_xy.add_widget(slb2) lo.add_widget(sliders_wh) lo.add_widget(sliders_xy) self.flo = FloatLayout() # circle canvas lo.add_widget(self.flo) # redraw cicle self.ev = Clock.schedule_interval(self.callback, .3) return lo However, to keep on refreshing the shape and position of circle on the canvas, we need to schedule a periodic event, clear the canvas to wipe out the existing circle and redraw it with instantaneous values of width, height, cx and cy. The following callback method has to be added in the App class − def callback(self, dt): self.flo.canvas.clear() with self.flo.canvas: Color(1, 1, 1) Ellipse( pos=(self.sl3.value, self.sl4.value), size=(self.sl1.value, self.sl2.value), angle_start=0, angle_end=360 ) You can now run the code. Exactly the same result will be obtained as with the “kv” file version. Print Page Previous Next Advertisements ”;