Search code examples
pythoninheritancekivychildren

Syntax for checking child interactions in kivy


I am learning kivy from a book that involves making a paint app. The author at one point introduces new buttons on a canvas class (inherited from Widget) and says that we have to check if the click received by the application on the canvas, also lies on one of its children. In that case, we would neglect the former and act on the latter. I thought of achieving this by looping through self.children, checking if the on_touch_down(touch) member function returns true for any child, and returning from the function if that was the case:

class CanvasWidget(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.my_color = get_color_from_hex('#FF0000')
        self.line_width=2
    def on_touch_down(self, touch):
        for child in self.children:
            if(child.on_touch_down(touch)):
                return
        with self.canvas:
            Color(rgba=self.my_color)
            touch.ud['current_line'] = Line(points=(touch.x, touch.y), width=self.line_width)
And this works fine.

However, I don't follow and would like to understand his shorthand syntax:

class CanvasWidget(Widget):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.my_color = get_color_from_hex('#FF0000')
        self.line_width=2
    def on_touch_down(self, touch):
        #I don't understand the following line
        if Widget.on_touch_down(self, touch):
            return
        #Widget refers to the parent class (I hope?) how does it check with the
        #children?
        
        with self.canvas:
            Color(rgba=self.my_color)
            touch.ud['current_line'] = Line(points=(touch.x, touch.y), width=self.line_width)

Any clarity is appreciated. Thanks!


Solution

  • The Widget class is the base class for all the kivy widgets, and it handles the propagation of touch events to its children via its on_touch_down() method. Rather than referencing the Widget base class directly, a better approach is to use the super() method, like this:

        if super(CanvasWidget, self).on_touch_down(touch):
            return True
    

    This does the propagation and returns True (to stop the propagation) if any of the children want the propagation stopped. The code in Widget that does this is:

        for child in self.children[:]:
            if child.dispatch('on_touch_down', touch):
                return True
    

    Since it does not directly reference the Widget base class, the super() method is safer if you decide to change the base class of CanvasWidget.