Skip to content
Advertisement

Kivy: best way to make a single widget containing different widgets and being able to access their properties in the kv file

I’m trying to make a class that would be a Slider + 2 Labels, one label showing the value of the slider, and one showing the name of the slider. The goal is to reuse this in lieu of Slider when convinient.

I am ending up creating properties in the my class MySlider reflecting the ones I am interested in in Slider. If, for example, I wanted to be able to also specify the color of the value label, I could do the same, add a property “value_label_color” to MySlider and set the label’s color in on_value_label_color()… Then in the kv file I would do something like that:

value_label_color: 1,0,1,0.15

This would work but could be very long if I had many widgets in my MySlider class.

I thought there may be a way to avoid all this and directly access the label’s color from the kv file, so I could do something like the following?

    MySlider:
        orientation: 'vertical'
        id: slider2
        name: 'hop'
        step: 20
        self.value_label.color: 1,1,1,0.15

But this doesn’t work.

Here is my minimal code as of now: .py:

from kivy.config import Config
from kivy.uix.boxlayout import BoxLayout
from kivy.uix.label import Label
from kivy.uix.slider import Slider
from kivy.app import App
from kivy.properties import NumericProperty, StringProperty


class MySlider(BoxLayout):
    name = StringProperty('Param')
    min = NumericProperty(0)
    max = NumericProperty(100)
    step = NumericProperty()

    def __init__(self, *args, **kwargs):
        super(MySlider, self).__init__(*args, **kwargs)

        self.value_label = Label()
        self.value_label.id = "value_label"
        self.slider = Slider()
        self.slider.bind(value=self._on_value)
        self.name_label = Label()

        self.value_label.text = str(self.slider.value)
        self.slider.orientation = 'vertical'

        self.add_widget(self.value_label)
        self.add_widget(self.slider)
        self.add_widget(self.name_label)

    def on_name(self, obj, val):
        self.name_label.text = val

    def on_min(self, obj, val):
        self.slider.min = val

    def on_max(self, obj, val):
        self.slider.max = val

    def on_step(self, obj, val):
        self.slider.step = val

    def _on_value(self, obj, val):
        self.value_label.text = str(self.slider.value)


class MyLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(MyLayout, self).__init__(**kwargs)


class test7App(App):
    def build_config(self, config):
        Config.set('kivy', 'exit_on_escape', '0')
        Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
        self.title = 'My Sliders'

    def build(self):
        return MyLayout()


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

and the kv file:

#:kivy 2.0.0


<MyLayout>:
    orientation : 'horizontal'

    canvas:
        Color:
            rgba: 1,1,1,0.15
        Rectangle:
            size: self.size
            pos: self.pos

    MySlider:
        orientation: 'vertical'
        id: slider1
        name: "hip"
        min: -30
        max: +60
        step: 1

    MySlider:
        orientation: 'vertical'
        id: slider2
        name: 'hop'
        step: 20

If you have any suggestion about how to get there in the nicest (and economical) way, I would be grateful.

Thanks a lot. C

Advertisement

Answer

You can do that all from the kv file. In fact, you don’t even need to define the MySlider class in the python code. You can modify your kv like this:

#:kivy 2.0.0

<MySlider@BoxLayout>:
    orientation: 'vertical'
    name: 'Param'
    min: 0
    max: 100
    step: 1
    value_label_color: 1,1,1,0.15
    
    Label:
        id: value_label
        text: str(slider.value)
        color: root.value_label_color
    Slider:
        id: slider
        orientation: root.orientation
        min: root.min
        max: root.max
        step: root.step
    Label:
        text: root.name
    


<MyLayout>:
    orientation : 'horizontal'

    canvas:
        Color:
            rgba: 1,1,1,0.15
        Rectangle:
            size: self.size
            pos: self.pos

    MySlider:
        orientation: 'vertical'
        id: slider1
        name: "hip"
        min: -30
        max: +60
        step: 1

    MySlider:
        orientation: 'horizontal'
        id: slider2
        name: 'hop'
        step: 20

and your python code simplifies to:

from kivy.config import Config
from kivy.lang import Builder
from kivy.uix.boxlayout import BoxLayout
from kivy.app import App


class MyLayout(BoxLayout):
    def __init__(self, **kwargs):
        super(MyLayout, self).__init__(**kwargs)


class test7App(App):
    def build_config(self, config):
        Config.set('kivy', 'exit_on_escape', '0')
        Config.set('input', 'mouse', 'mouse,multitouch_on_demand')
        self.title = 'My Sliders'


    def build(self):
        return MyLayout()


if __name__ == '__main__':
    test7App().run()
User contributions licensed under: CC BY-SA
10 People found this is helpful
Advertisement