Search code examples
pythonkivykivy-languagetogglebutton

Creating Kivy customized ToggleButtons


I am trying to create customized ToggleButtons in Kivy. For the most part I have succeeded except when I pair them into group. When one of the buttons is pressed down and I press onto another, the color of the formerly pressed button won't return to normal, unless I hover over it. Is there a way to make it return to it's color, when it gets unpressed by clinking another button in the group?

Please help out.

Here is the code:

from kivy.app import App
from kivy.graphics import RoundedRectangle, Color
from kivy.uix.behaviors import ButtonBehavior, ToggleButtonBehavior
from kivy.uix.button import Button
from kivy.uix.togglebutton import ToggleButton
from kivy.uix.widget import Widget
from kivy.lang import Builder
from kivy.animation import Animation
from kivymd.uix.behaviors import HoverBehavior
from kivy.properties import ObjectProperty
import time

Builder.load_file('rounding_button.kv')


class MyLayout(Widget):

    def unlock_button(self):
        if self.ids.disabled_button_2.disabled:
            self.ids.disabled_button_2.disabled = False
        else:
            self.ids.disabled_button_2.disabled = True

    @staticmethod
    def run_method():
        time.sleep(3)

class RoundedButton(Button, ButtonBehavior, HoverBehavior):

    button_image = ObjectProperty(None)  # Object property for picture in the button

    def __init__(self, **kwargs):
        super(RoundedButton, self).__init__(**kwargs)
        self.hover_anim = None
        self.press_anim = None
        self.image_anim = None
        self.text = ""
        self.font_size = 50
        self.background_color = (0, 0, 0, 0)
        self.disabled = True

    def on_press(self, *args):
        self.press_anim = Animation(col=(51/255, 26/255, 0, 1/2), duration=0.15)  # Color for pressed button
        self.press_anim.start(self)
        self.image_anim = Animation(color=(102 / 255, 61 / 255, 0, 1), duration=0.15)  # Color for picture when button pressed
        self.image_anim.start(self.button_image)

    def on_release(self, *args):
        self.press_anim = Animation(col=(158/255, 87/255, 0, 1), duration=0.15)  # Color after button is released
        self.press_anim.start(self)
        self.image_anim = Animation(color=(1, 1, 1, 1), duration=0.15)  # Color for picture when button released
        self.image_anim.start(self.button_image)

    def on_enter(self, *args):
        if not self.disabled:
            print("Hovered!")
            self.hover_anim = Animation(col=(102/255, 61/255, 0, 1), duration=0.15)  # Color when hovered over button
            self.hover_anim.start(self)
            self.image_anim = Animation(color=(102 / 255, 61 / 255, 0, 1), duration=0.15)  # Color for picture when hovered over
            self.image_anim.start(self.button_image)

    def on_leave(self, *args):
        if not self.disabled:
            print("Moved away!")
            self.hover_anim = Animation(col=(158/255, 87/255, 0, 1), duration=0.15)  # Color when moved away from button
            self.hover_anim.start(self)
            self.image_anim = Animation(color=(1, 1, 1, 1), duration=0.15)  # Color for picture when moved away from button
            self.image_anim.start(self.button_image)

class RoundedToggleButton(ToggleButton, ToggleButtonBehavior, HoverBehavior):

    toggle_button_image = ObjectProperty(None)

    def __init__(self, **kwargs):
        super(RoundedToggleButton, self).__init__(**kwargs)
        self.down_anim = None
        self.hover_anim = None

    def on_press(self):
        pass

    def on_release(self):
        pass

    def on_state(self, widget, value):
        if value == "down":
            self.down_anim = Animation(col=(0, 134/255, 179/255, 1), duration=0.2)
            self.down_anim.start(self)
        else:
            self.down_anim = Animation(col=(0, 191/255, 1, 1), duration=0.2)
            self.hover_anim.start(self)

    def on_enter(self, *args):
        self.hover_anim = Animation(col=(128/255, 223/255, 1, 1), duration=0.15)  # Color when hovered over button
        self.hover_anim.start(self)

    def on_leave(self):
        if self.state == "normal":
            self.hover_anim = Animation(col=(0, 191/255, 1, 1), duration=0.15)  # Color when moved away from button
            self.hover_anim.start(self)
        else:
            self.hover_anim = Animation(col=(0, 134/255, 179/255, 1), duration=0.15)  # Color when moved away from button
            self.hover_anim.start(self)

class AwesomeApp(App):

    def build(self):
        return MyLayout()

if __name__ == '__main__':
    AwesomeApp().run()

kv file:

<RoundedButton>
    button_image: button_image
    id: disabled_button
    col: (158/255, 87/255, 0, 1)
    canvas.before:
        Color:
            rgba: (51/255, 26/255, 0, 1/2) if self.disabled else self.col
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [32]
    BoxLayout:
        size: self.parent.size
        Image:
            id: button_image
            source: '/Users/f22daniel/PycharmProjects/Griraffe/smart_contract_development/Kivy_App/copy_link.png'
            center_x: self.parent.center_x
            center_y: self.parent.center_y
            pos_hint: {"center_x": 0.5, "center_y": 0.5}
            keep_ratio: True
            allow_stretch: True
            color:  (51/255, 26/255, 0, 1/2) if disabled_button.disabled else (1,1,1,1)

<RoundedToggleButton>
    toggle_button_image: toggle_button_image
    id: toggle_button_image
    col: (0, 191/255, 1, 1)
    background_color: (0, 0, 0, 0)
    canvas.before:
        Color:
            rgba: self.col
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [42]


<MyLayout>
    BoxLayout:
        orientation: 'vertical'
        size: root.width, root.height
        padding: 5
        spacing: 5

        Button:
            text: 'Submit'
            on_release: root.unlock_button()
            font_size: 32
            background_normal: ''
            background_color: (0,0,1,1)

        RoundedButton:
            id: disabled_button_2
            on_release: root.run_method()

        BoxLayout:
            orientation: 'horizontal'
            size: root.width, root.height
            padding: 2
            spacing: 2
            RoundedToggleButton:
                group: "toggles"
            RoundedToggleButton:
                group: "toggles"
            RoundedToggleButton:
                group: "toggles"

And here the screenshots: enter image description here enter image description here enter image description here

I need the formally pressed button to return to it's original color, when another one in the group is pressed.


Solution

  • In the "on_state" method of your toggle button replace self.hover_anim.start(self) with self.down_anim.start(self) in the "else" branch and you should get the correct behavior.