omarPython
omarPython

Reputation: 31

How to make circular button in kivy using button behavior?

I think there is a way to do it in kivy rather than going round the python code.

my code in the kv file:

ButtonBehavior:
     source: "round-icon.png"

the app crashes saying

AttributeError: 'ButtonBehavior' object has no attribute 'register_event_type'

round-icon.png is circular icon. The last thing that I will appreciate recommendation, How to set this button to certain size is the window?

Upvotes: 3

Views: 8214

Answers (2)

Peter Badida
Peter Badida

Reputation: 12179

You need to make a custom rule(/class) that has the behavior and you need to include Image as el3phanten stated, yet it won't work only that way, because it'll return you a missing class.

Kv language creates a widget from either already registered classes, or custom classes, which may be Python + Kv (that thing you define in both files), or kv only(dynamic). I guess your intention is the dynamic one, so I'll go this way:

from kivy.app import App
from kivy.lang import Builder

kv = """
<Test@ButtonBehavior+Image>:
    canvas:
        Color:
            rgba: 1, 0, 0, .3
        Rectangle:
            size: self.size
            pos: self.pos
BoxLayout:
    Button:
    Test:
        source: 'image.png'
"""

class TestApp(App):
    def build(self):
        return Builder.load_string(kv)

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

The behavior needs to be first similar to inheriting in Python, then you may add another parts, such as Image.

There's however a big problem for you in this implementation, which is visible with the Rectangle in my example. That is an area that captures every touch, which means you might have a circular image, yet the touch are is still a rectangle.

To get around that you'll need to check for a collision, thus you need to switch from dynamic class to the one that's defined even in Python, so that you can make custom collisions. Example.

That, however, might be really costly even for a single button, therefore a better solution is using something like this:

from kivy.app import App
from kivy.lang import Builder
from kivy.properties import NumericProperty
from kivy.uix.behaviors import ButtonBehavior
from kivy.uix.image import Image

kv = """
<RoundButton>:
    canvas:
        Color:
            rgba: 1, 0, 0, .3
        Rectangle:
            size: self.size
            pos: self.pos
        Color:
            rgba: 0, 0, 1, 1
        Rectangle:
            size:
                [self.size[0] - root.OFFSET_x,
                self.size[1] - root.OFFSET_y]
            pos:
                [self.pos[0] + root.OFFSET_x / 2.0,
                self.pos[1] + root.OFFSET_y / 2.0]
BoxLayout:
    Button:
    RoundButton:
        source: 'image.png'
        on_release: print('Release event!')
"""


class RoundButton(ButtonBehavior, Image):
    OFFSET_x = NumericProperty(100)
    OFFSET_y = NumericProperty(200)

    def on_touch_down(self, touch):
        left = touch.x >= self.pos[0] + self.OFFSET_x / 2.0
        down = touch.y >= self.pos[1] + self.OFFSET_y / 2.0
        up = touch.y <= self.pos[1] + self.size[1] - self.OFFSET_y / 2.0
        right = touch.x <= self.pos[0] + self.size[0] - self.OFFSET_x / 2.0

        if left and down and up and right:
            print('collided!')
            self.dispatch('on_release')
        else:
            print('outside of area!')


class TestApp(App):
    def build(self):
        return Builder.load_string(kv)

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

or a really low number of points to a better area coverage, yet higher than for a simple rectangle.

How to set this button to certain size is the window?

Use size_hint or directly Window.size to manipulate your widget's size. size_hint is definitely better unless you want to have everything in Window, i.e. without any proper Layout

Upvotes: 0

el3ien
el3ien

Reputation: 5405

Try importing Image also:

Image+ButtonBehavior:
     source: "round-icon.png"

Upvotes: 1

Related Questions