Dolf Andringa
Dolf Andringa

Reputation: 2170

Kivy: Adding a label and image to a button for a reusable widget

I am making a reusable widget in kivy that contains a couple of child widgets. One of those child widgets is a button that I want to have a text centered on the button, and a small icon aligned on the right of the button. I am trying to achieve it by adding a StackLayout to the button, but because the button is a widget, the stacklayout's position isn't inside the button. Since I am going to reuse the widget in multiple places, I don't see how I can make the position relative to the parent widget.

With the current example, the image isn't displayed at all and the text is displayed at the bottom of the app.

label in wrong position

A complete minimal working example is on https://github.com/dolfandringa/kivy_playground/blob/master/button_label_image/

But this is the relevant code for my widget:

from pathlib import Path

from kivy.uix.button import Button
from kivy.uix.image import Image
from kivy.uix.label import Label
from kivy.uix.stacklayout import StackLayout

ICON = Path(__file__).parent.resolve() / 'caret-down-solid.png'


class MyWidget(StackLayout):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.size_hint_y = None
        self.height = '32dp'
        self.button = Button()
        button_layout = StackLayout()
        self.button.add_widget(button_layout)
        label1 = Label(text="[color=000000]text1[/color]",
                       markup=True)

        icon = Image(source=str(ICON), size=(16, 16))
        button_layout.add_widget(label1)
        button_layout.add_widget(icon)
        self.add_widget(self.button)

and this is how the widget is being used in a sample app kv file:

#:import MyWidget widgets
GridLayout:
    canvas.before:
        Color:
            rgb: 1,1,1
        Rectangle:
            size: self.size
    cols: 1
    Button:
        text: "hello"
        size_hint_x: None
        size_hint_y: None
    MyWidget:
        size_hint_x: None
        width: root.width*0.5
    Button:
        text: "hello2"
        size_hint_x: None
        size_hint_y: None

Upvotes: 0

Views: 627

Answers (2)

Dolf Andringa
Dolf Andringa

Reputation: 2170

Another option in addition to the one from @amras is to use a RelativeLayout like this:

class MyWidget(StackLayout):

    def __init__(self, *args, **kwargs):
        super().__init__(*args, **kwargs)
        self.size_hint_y = None
        self.height = '32dp'
        self.button = Button(
            text="text1",
            pos_hint={'center_x': 0.5, 'center_y': 0.5},
            size_hint=(1, 1)
        )
        button_layout = RelativeLayout()
        self.add_widget(button_layout)
        button_layout.add_widget(self.button)
        icon = Image(source=str(ICON), size=(16, 16), size_hint=(None, None))
        icon.reload()
        icon.pos_hint = {'center_x': 0.95, 'center_y': 0.5}
        button_layout.add_widget(icon)

Upvotes: 0

amras
amras

Reputation: 1599

You can change the widget py file like below to achieve your target:

from kivy.uix.boxlayout import BoxLayout
from kivy.lang import Builder

Builder.load_string("""
<MyWidget>:
    size_hint: 1, None
    height: '32dp'
    Button:
        text: 'text1'
        icon_size: 16, 16
        canvas:
            Rectangle:
                source: 'caret-down-solid.png'
                size: self.icon_size
                pos: self.pos[0] + self.width - self.icon_size[0], self.pos[1] + self.icon_size[1] / 2
""")

class MyWidget(BoxLayout):
    pass

Here a custom property icon_size is defined for Button and used it to adjust the size and position of the icon inside Button.

Upvotes: 1

Related Questions