Search code examples
pythonkivykivy-languagekivymd

How to make an irregular quadrilateral shaped button in kivy python?


I am trying to make an android app with kivy. Its user interface begins with these two buttons named '2D' and '3D'. Please help me to create a irregular quadrilateral shaped button with kivy.

enter image description here


Solution

  • You can extend Button to behave as though it is two Buttons:

    class MyButton(Button):
        my_state = StringProperty('')  # this will be 'b1' or 'b2', even when button is not down
        my_down_image = StringProperty('')
        def on_touch_down(self, touch):
            if self.collide_point(*touch.pos):
                rx, ry = self.to_widget(*touch.pos, relative=True)
                if ry > self.height/2.0:  # more complex geometry calculation required
                    self.my_down_image = 'B2Down.png'
                    self.my_state = 'b2'
                else:
                    self.my_down_image = 'B1Down.png'
                    self.my_state = 'b1'
            return super(MyButton, self).on_touch_down(touch)
    

    The MyButton class adds two properties to Button, the my_state andmy_down_image properties. The my_state property will be b1 or b2 depending on which sub-button was pressed (set by on_touch_down()). The my_down_image property is set to either B1Down.png or B2Down.png which depict what we want the MyButton to look like when B1 or B2 is pressed. The simple y-coordinate compare that is in the above code will not work, and must be more complicated to correctly determine which sub-button was pressed. The MyButton can be used in kv like this:

    MyButton:
        background_normal: 'B1andB2.png'
        on_press: app.do_butt_press(self)
        on_release: app.do_butt_release(self)
    

    where the app methods look like:

    def do_butt_press(self, button):
        print('on_butt_press', button.state, button.my_state)
    
    def do_butt_release(self, button):
        print('on_butt_release', button.state, button.my_state)
    

    and in kv:

    <-MyButton>:
        state_image: self.background_normal if self.state == 'normal' else self.my_down_image
        disabled_image: self.background_disabled_normal if self.state == 'normal' else self.background_disabled_down
        canvas:
            Color:
                rgba: self.background_color
            BorderImage:
                border: self.border
                pos: self.pos
                size: self.size
                source: self.disabled_image if self.disabled else self.state_image
            Color:
                rgba: 1, 1, 1, 1
            Rectangle:
                texture: self.texture
                size: self.texture_size
                pos: int(self.center_x - self.texture_size[0] / 2.), int(self.center_y - self.texture_size[1] / 2.)
    

    The above kv rule is mostly just a copy of the default Button rule used by Kivy. The only change is the use of my_down_image in the state_image definition.

    For this example, the B1andB2.png can be:

    B1andB2.png

    B1Down.png:

    B1Down.png

    and B2Down.png: B2Down.png