Search code examples
pythonkivy

How can I detect when touch is in the children widget in kivy


How I can detect when touch position in a children widget of game grid? When I want call children method mark_label(). Thank you.

class GameGrid(GridLayout):

    def on_touch_move(self, touch):
        #which label is collision  
        print(str(touch.pos))


class StartScreen(Screen):

    level = Level(mode, 1)

    def __init__(self,**kwargs):
        super().__init__(**kwargs)
        self.create_level()

    def create_level(self):
        self.ids.game_grid.clear_widgets()

        labels = self.level.get_letters_label()
        for f in range(len(labels)):
            self.ids.game_grid.add_widget(labels[f])

Solution

  • Use self.collide_points() method to check for collision of the touch with the widget of interest.

    Snippets

    class CreateLabel(Label):

    def on_touch_down(self, touch):
        if self.collide_point(*touch.pos):
            # TODO
            # call method mark_label()
            if touch.button == "right":
                print("Right mouse clicked on {}".format(self.text))
            elif touch.button == "left":
                print("Left mouse clicked on {}".format(self.text))
            else:
                print(self.id)
            return True
        return super(CreateLabel, self).on_touch_down(touch)
    

    Programming Guide » Events and Properties » Dispatching a Property event

    If the touch falls inside of our widget, we change the value of pressed to touch.pos and return True, indicating that we have consumed the touch and don’t want it to propagate any further.
    ...
    Finally, if the touch falls outside our widget, we call the original event using super(…) and return the result. This allows the touch event propagation to continue as it would normally have occurred.

    Example

    main.py

    from kivy.app import App
    from kivy.uix.gridlayout import GridLayout
    from kivy.uix.label import Label
    
    
    class CreateLabel(Label):
    
        def on_touch_down(self, touch):
            if self.collide_point(*touch.pos):
                if touch.button == "right":
                    print("Right mouse clicked on {}".format(self.text))
                elif touch.button == "left":
                    print("Left mouse clicked on {}".format(self.text))
                else:
                    print(self.id)
                return True
            return super(CreateLabel, self).on_touch_down(touch)
    
    
    class RootWidget(GridLayout):
    
        def __init__(self, **kwargs):
            super(RootWidget, self).__init__(**kwargs)
            self.build_board()
    
        def build_board(self):
            # make 9 label in a grid
            for i in range(0, 9):
                label = CreateLabel(id=str(i), text="Label {}".format(i))
                self.add_widget(label)
    
    
    class TestApp(App):
    
        def build(self):
            return RootWidget()
    
    
    if __name__ == '__main__':
        TestApp().run()
    

    test.kv

    #:kivy 1.10.0
    
    <CreateLabel>:
        canvas.before:
            Color:
                rgba: 0, 1, 1, 0.5  # 50% blue
            Rectangle:
                size: self.size
                pos: self.pos
        font_size: 30
        on_touch_down: self.on_touch_down
    
    <RootWidget>:
        rows: 3
        cols: 3
        row_force_default: True
        row_default_height: 150
        col_force_default: True
        col_default_width: 150
        padding: [10]
        spacing: [10]
    

    Output

    Img01 - Clicked on Label 3 Img02 - Clicked on Label 8