Search code examples
pythonkivykivy-languagekivymd

How to make the border appear when hovering over a button in Kivy


I started learning Kivy recently and I can't believe that such simple things like creating buttons and adding basic behaviours to them like hovering over them etc are so difficult and unintuitive.

My question is how can I make the border appear around a button when I hover over it with a mouse?

I have this simple "main menu" design and I want to make the button change its appearance as on the screen below:

enter image description here

The only thing that I can't figure out is how to make the border appear when hovering over the buttons (although finding out how to make a hover effect in Kivy took also a lot of time...).

I've literally spent the last few hours googling it and searching for the solution here on Stack Overflow but I wasn't able to find anything related to this problem.

I know that I can add borders and make a button that is surrounded with borders by including the following code in my Kivy file:

canvas.before:    
     Color:
         rgba: #some color
     Line:
        rounded_rectangle: (self.pos[0], self.pos[1], self.size[0], self.size[1], self.border_radius)
        width: 2

But I don't know how to get canvas.before in my ButtonMenu class updated after a hover.

I also tried to combine RoundedRectangle and Line so that the border is already added even when the button is black and only the background_color is updated, but it didn't really give me the results that I want.

Below is my code in Python file:

from kivy.lang.builder import Builder
from kivy.properties import ListProperty
from kivy.uix.button import Button
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.core.window import Window
from kivymd.uix.behaviors.hover_behavior import HoverBehavior
Window.size = (1280, 720)


class MainMenu(Screen):
    pass


class WindowManager(ScreenManager):
    pass


class ButtonMenu(Button, HoverBehavior):
    background = ListProperty((0, 0, 0, 1))
    color = ListProperty((1, 1, 1, 1))

    def on_enter(self):
        self.background = (1, 222/255, 89/255, 1)
        self.color = (0, 0, 0, 1)

    def on_leave(self):
        self.background = (0, 0, 0, 1)
        self.color = (1, 1, 1, 1)


class TicTacToeUltimateApp(App):
    def build(self):
        return Builder.load_file('tictactoeultimate.kv')


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

My Kivy file:

WindowManager:
    MainMenu:

<MainMenu>:
    name: 'main_menu'

    FloatLayout:
        orientation: 'horizontal'
        size: 1280, 720
        canvas.before:
            Color:
                rgba: (1, 222/255, 89/255, 1)
            Rectangle:
                pos: self.pos
                size: self.size

        ButtonMenu:
            text: 'PLAY'
            pos_hint: {'center_x': .5, 'center_y': .5}

        ButtonMenu:
            text: 'SETTINGS'
            pos_hint: {'center_x': .5, 'center_y': .35}

        ButtonMenu:
            text: 'ABOUT'
            pos_hint: {'center_x': .5, 'center_y': .2}



<ButtonMenu>
    background_color: 0, 0, 0, 0
    background_normal: ''
    size_hint: 0.3, 0.11
    font_size: 26
    font_name: 'Roboto'
    bold: True
    canvas.before:
        Color:
            rgba: self.background
        RoundedRectangle:
            size: self.size
            pos: self.pos
            radius: [28]
        Line:
            rounded_rectangle: (self.pos[0], self.pos[1], self.size[0], self.size[1], self.border_radius)
            width: 2
    `

To get the hover effect I followed this tutorial, but it just shows how to get the change of the background color to be updated, not how to add borders:

https://www.youtube.com/watch?v=fKFpxud0O6c

Furthermore, I found this video on how to create a border around a button, but it just shows how to create a static button with a border. Basically, I still don't know how to make this border to be updated:

https://www.youtube.com/watch?v=Xv57jB_Xvqo&t=366s

Thank you in advance for looking into it.


Solution

  • Sometimes the simplest solutions slip our minds and we focus on difficult things. Following this way, the border appears when hovering over a button in Kivy

    Solution:

    1. Add a second Color in your canvas.before:. So write: Color: rgba: (0, 0, 0, 1)

    2. In your rounded_rectangle of Line, remove self.border_radius and then write , 28

    Complete code:

    WindowManager:
        MainMenu:
    
    <MainMenu>:
        name: 'main_menu'
    
        FloatLayout:
            orientation: 'horizontal'
            size: 1280, 720
            canvas.before:
                Color:
                    rgba: (1, 222/255, 89/255, 1)
                Rectangle:
                    pos: self.pos
                    size: self.size
    
            ButtonMenu:
                text: 'PLAY'
                pos_hint: {'center_x': .5, 'center_y': .5}
    
            ButtonMenu:
                text: 'SETTINGS'
                pos_hint: {'center_x': .5, 'center_y': .35}
    
            ButtonMenu:
                text: 'ABOUT'
                pos_hint: {'center_x': .5, 'center_y': .2}
    
    
    
    <ButtonMenu>
        background_color: 0, 0, 0, 0
        background_normal: ''
        size_hint: 0.3, 0.11
        font_size: 26
        font_name: 'Roboto'
        bold: True   
        canvas.before:
            Color:
                rgba: self.background
            RoundedRectangle:
                size: self.size
                pos: self.pos
                radius: [28]
            Color:
                rgba: (0, 0, 0, 1)  # separate color for line border
            Line:
                rounded_rectangle: (self.pos[0], self.pos[1], self.size[0], self.size[1], 28)
                width: 2