Kivy Tutorials – How to create multiple widgets in Kivy UI and bind them to touch event for moving them

Kivy Tutorials – How to create multiple widgets in Kivy UI and bind them to touch event for moving them

Kivy_touch_events

Test Environment 

Fedora 31 with kivy installed

What is Kivy –

Kivy is a Python framework which is used to develop multi touch software application for various devices like Andriod, IOS, Tablets and Desktops.

In this video we will try to build a very basic Kivy application and include few Canvas Widgets. Once the Widgets are placed onto our Root Widgets, we will try to bind the touch events for these widgets in such a way that they will help us grab any particular instance of Canvas Widget and drag it as per our convenience.

Before going into the details of the example lets get some basic information about a few terms

on_touch_down

– This is the event that gets triggered when a particular widget is clicked

on_touch_move

– This is the event that gets triggered when a particular widget is clicked and dragged without releasing the widget.

on_touch_up

– This is the event that gets triggered when a particular widget is released.

If you are interested in reading instead of watching the video, i have include the step by step procedure for the same below the video.

Procedure –

Step1: Create application named MoveWidgetApp which will launch an empty Window with Widget as the root element.

Here we are going to use Widget element and extend it using our Custom Widget Class MyWidget which will be passed as the root Widget when the application is launched

MoveWidget Kivy application
[admin@fed31 movewidget]$ cat movewidget.py 
#!/usr/bin/env python

import kivy
kivy.require('1.11.1')

from kivy.app import App
from kivy.uix.widget import Widget

class MyWidget(Widget):
    pass

class MoveWidgetApp(App):

    def build(self):
        my = MyWidget()
        return my

if __name__ == '__main__':
    MoveWidgetApp().run()

Step2: Create movewidget.kv file to add two child rectangle widgets with a particular size

Here we have defined a new class named MoveWidget in which we have defined canvas to draw the rectangle widget. This child widget we will be adding to our root widget ie. MyWidget as shown below.

moveWidget kv file
[admin@fed31 movewidget]$ cat movewidget.kv 
#:kivy 1.11.1

<MoveWidget>:
    canvas:
        Rectangle:
            size: 100, 50
            pos: self.pos

<MyWidget>:
    MoveWidget:
        pos: 100, 100
    MoveWidget:
        pos: 100, 300

We also need to define our MoveWidget class in our main application file as shown below.

MoveWidget Kivy application
[admin@fed31 movewidget]$ cat movewidget.py 
#!/usr/bin/env python

import kivy
kivy.require('1.11.1')

from kivy.app import App
from kivy.uix.widget import Widget

class MoveWidget(Widget):
    pass

class MyWidget(Widget):
    pass

class MoveWidgetApp(App):

    def build(self):
        my = MyWidget()
        return my

if __name__ == '__main__':
    MoveWidgetApp().run()

Step3: Define and Bind the Widget events like touch, move and release

Until Step2, we have created our root Widget Application with two Child Widget of Rectangle shape added. Now, we will define the three Widget functions that are.

on_touch_down, on_touch_up and on_touch_move in such a way that we can drag our Child Widgets in the horizontal direction individually.

We need to initialize our MoveWidget class using __init__ if we want to define our UI and call super as shown below.

on_touch_down – In this function we need to first validate touch points whether they are within the Widget Collide area. If that condition is True, we are grabbing that Widget instance using touch.grab(self)

on_touch_up – In this function we are checking whether the current widget grabbed and if that condition is True, we are ungrabbing that current Widget and returing True

on_touch_move – In this function once the Widget is grabbed and if we are moving the Widget in horizontal direction we are updating the Widget x coordinate in such a way that it moves in the direction where touch is being dragged.

We also need to make sure to return the touch postion to the Widgets parent class in case these events are not handled here in our Custom MoveWidget class by using super.

We need to modify our MoveWidget class as shown below

MoveWidget Kivy application with touch event functions
class MoveWidget(Widget):

    def __init_(self, **kwargs):
        super(MoveWidget, self).__init__(**kwargs)
    
    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            #print("Child Widget touched")
            touch.grab(self)
            return True
        return super(MoveWidget, self).on_touch_down(touch)

    def on_touch_up(self, touch):
        if touch.grab_current is self:
            touch.ungrab(self)
            return True
        super(MoveWidget, self).on_touch_up(touch)

    def on_touch_move(self, touch):
        if touch.grab_current is self:
            if touch.x < self.width:
                self.x = touch.x
            else:
                self.x = touch.x - self.width
            return True
        return super(MoveWidget, self).on_touch_move(touch)

Now, we have our two Child Widgets which we can move them in horizontal direction individually using the touch events.

Hope you enjoyed reading this article or watching the video. Thank you..