Jacek_Kozmic
Jacek_Kozmic

Reputation: 68

Kivy buttons not working as intended

I've started making my first kivy app a few days ago and everything went fine up till one point.

I have a Label which has GridLayout inside and 256 buttons (PaletteColorButton) that are supposed to represent palette. I created an on_touch_down method for this class and try to click on any of the buttons, they all execute what's inside of on_touch_down.

Here's the most important part of my code:

class PaletteLabel(ToolBarLabel):
    def make_palette(self, layout):
        for i in range(0, 256):
            palette_color_button = PaletteColorButton()
            with palette_color_button.canvas:
                Color(i/255, i/255, i/255, 1)
            layout.add_widget(palette_color_button)


class PaletteColorButton(Button):

    def on_touch_down(self, touch):
        if touch.is_double_tap:
            print(self.pos)


class BamEditor(App):
    Config.set('kivy', 'window_icon', r'.\static\program_icon\BamEditor-icon.png')
    def build(self):
        main_label = MainLabel()
        main_label.ids['palettelabel'].make_palette(main_label.ids['palettelayout'])
        return main_label

And here's the data from .kv file:

<PaletteLabel>:
    height: 160
    width: 640


<PaletteColorButton>:
    size:(20,20)
    canvas.after:
        Rectangle:
            pos: self.x + 1 , self.y + 1
            size: self.width - 2, self.height - 2
<MainLabel>:
    PaletteLabel:
        id: palettelabel
        pos: (self.parent.x + 120, self.parent.y + 20)

        GridLayout:
            id: palettelayout
            cols: 32
            rows: 8

            pos: self.parent.x , self.parent.y
            size: self.parent.width, self.parent.height 

I want to have only the clicked button's pos printed, but instead I get positions of all 256 buttons, does anyone know how to achieve that? Ofc, I can use on_press instead and it works, but I'd like my buttons to have different behavior when tapped once and different when tapped twice. Thank you for help.

Upvotes: 0

Views: 1490

Answers (1)

Tshirtman
Tshirtman

Reputation: 5947

from the kivy programming guide:

By default, touch events are dispatched to all currently displayed widgets. This means widgets receive the touch event whether it occurs within their physical area or not.

[…]

In order to provide the maximum flexibility, Kivy dispatches the events to all the widgets and lets them decide how to react to them. If you only want to respond to touch events inside the widget, you simply check:

def on_touch_down(self, touch):
    if self.collide_point(*touch.pos):
        # The touch has occurred inside the widgets area. Do stuff!
        pass

https://kivy.org/docs/guide/inputs.html#touch-events

When you don't want to manage the touch in this button, (so when the collision test fails), you should let the event dispatch to the rest of the widget tree

    return super(WidgetClass, self).on_touch_down(touch)

Upvotes: 3

Related Questions