KIVY: image + label inside dynamic buttons

I want to show an Image + shortcut inside dynamic buttons created in a for loop. The problem is that it only displays the image layout + labels in the last button. How can I display it in all buttons?

main.py

class HomeScreen(Screen):
    grid_l = ObjectProperty(None)
    top_lbl = ObjectProperty(None)

    def search_btn_pressed(self):
        grid = self.grid_l
        grid.bind(minimum_height=grid.setter('height'),
                     minimum_width=grid.setter('width'))

        for i in range(3):
                layout = GridLayout(cols=1)
                print layout
                img = Image(source='kivy.png')
                print img
                lbl = Label(text='label')
                layout.add_widget(img)
                layout.add_widget(lbl)

                btn1 = Button(size_hint=(1, None))
                btn1.text = '%r' % i
                btn1.add_widget(layout)

                grid.add_widget(btn1)

      

.kv

#:kivy 1.7.2

<HomeScreen>:
    scroll_view: scrollviewID
    top_lbl: lblID
    grid_l: gridlayoutID
    AnchorLayout:
        size_hint: 1, .1   
        pos_hint: {'x': 0, 'y': .9}
        anchor_x: 'center'
        anchor_y: 'center'
        Label:
            id: lblID
            text: 'Button Tester'
    Button:
        size_hint: 1, .1   
        pos_hint: {'x': 0, 'y': .8}
        text: 'Press me!'
        on_release: root.search_btn_pressed()
    ScrollView:
        id: scrollviewID
        orientation: 'vertical'
        pos_hint: {'x': 0, 'y': 0}
        size_hint: 1, .8
        bar_width: '8dp'
        GridLayout:
            id: gridlayoutID
            cols: 1
            size_hint: 1, None
            row_default_height: 40
            row_force_default: False

      

screenshot

+3


source to share


1 answer


It doesn't actually show up just for the last button - it shows up for every button, but in the same position. The problem is that Button

it is not a layout and as such does not layout its children. So, GridLayout

for each button, it is displayed in 0, 0

with a size 100, 100

relative to the start of the closest relative parent (in this case GridLayout

grid_l

, because it is contained in ScrollView

).

When you add widgets to a non-layout widget, you need to position those widgets by setting position and size. Please note that you must set the actual pos

(or x

and y

) and size

(or width

and height

) - you cannot use pos_hint

or size_hint

as this is only handled by layouts.

This can be done easily using dynamic classes in the kv language :

<CustomButton@Button>:
    image_source: ''
    subtext: ''
    GridLayout:
        height: self.parent.height  # match the button height
        width: 100                  # set to whatever you would like
        pos: self.parent.pos        # match the button position
        cols: 1
        Image:
            source: root.image_source
        Label:
            text: root.subtext

      

To use a dynamic class, you will need to import Factory

:



from kivy.factory import Factory

      

Then in your loop:

for i in range(3):
    btn = Factory.CustomButton(text=str(i), size_hint=(1, None),
                               image_source='kivy.png', subtext='label')
    grid.add_widget(btn)

      

Finally, side of the note: you create new bindings grid_l

each time it is called search_btn_pressed()

. These bindings only need to be created once. You can bind once in Python by moving those bindings to HomeScreen.__init__()

, but again, this is easier in kv:

    GridLayout:
        id: gridlayoutID
        cols: 1
        size_hint: 1, None
        row_default_height: 40
        row_force_default: False
        height: self.minimum_height   # bind height to minimum_height
        width: self.minimum_width     # bind width to minimum_width

      

+3


source







All Articles