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

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

Kivy_multiple_widgets_movement

Here 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.

Test Environment 

Fedora 31
Kivy 1.11.1

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.

What are Touch Events

  • 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 intereseted in watching the video. Here is the YouTube video on the same step by step procedure outlined below.

Procedure

Step1: Create movewidget.py

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.

[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

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.

[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.

[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 now, 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.

[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):

    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 &lt; self.width:
                self.x = touch.x
            else:
                self.x = touch.x - self.width
            return True
        return super(MoveWidget, self).on_touch_move(touch)

Hope you enjoyed reading this article. Thank you..