Search code examples
pythonkivykivy-language

Problem adding touch event/click functionality to a widget with Kivy


I was wondering if someone could help me add some touch event/click functionality to a widget. I've tried a few things, including the following, which results in nothing happening at all:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color

class MyWidget(Widget):
    def __init__(self,**kwargs):
        super(MyWidget, self).__init__(**kwargs)
        
        with self.canvas:
            Color(22.0/255.0, 24.0/255.0, 72.0/255.0, 1)
            self.bg=Rectangle(pos=self.pos, size=self.size)

class MyApp(App):
    def build(self):
        root = Widget()
        btn = MyWidget(pos=(50,50), size=(50,50))
        btn.bind(on_release=self.widgetClick)
        root.add_widget(btn)
        return root
    
    def widgetClick(self, obj):
        print("Click")
        
MyApp().run()

As well as this, which results in the event being fired anytime there's a click within the window, and not just on the widget:

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.graphics import Rectangle, Color

class MyWidget(Widget):
    def __init__(self,**kwargs):
        super(MyWidget, self).__init__(**kwargs)
        
        with self.canvas:
            Color(22.0/255.0, 24.0/255.0, 72.0/255.0, 1)
            self.bg=Rectangle(pos=self.pos, size=self.size)

    def on_touch_down(self, touch):
        print("Touch")

class MyApp(App):
    def build(self):
        root = Widget()
        btn = MyWidget(pos=(50,50), size=(50,50))
        root.add_widget(btn)
        return root
        
MyApp().run()

So my question is, what is the proper way to go about this, or what am I doing wrong? If it wasn't obvious I'm quite new to Kivy, as I've usually created my Python GUIs using PySimpleGUI, but due to a limitation I've encountered I've decided to try out Kivy.

Any help is greatly appreciated!


Solution

  • on_touch_down does what you want, but you need to combine it with a collision check:

    def on_touch_down(self, touch):
        if not self.collide_point(*touch.pos):
            return False
    

    If you want to use on_release as in your first example, your widget needs to inherit from ButtonBehavior:

    class YourWidget(ButtonBehavior, Widget):
        ...