Search code examples
pythonkivykivy-language

Kivy nested BoxLayout stacks widgets on bottom left corner


I'm trying do dynamically build a Kivy layout with a vertical BoxLayout containing a varying number of custom MyRow widgets that can change at runtime. layout example each row is an horizontal BoxLayout

I'm not using a GridLayout because MyRow layout is being developed and can change in the near future adding widgets etc. like this example layout example 2

But with the code below I only get small widgets stacked on top of each other in the bottom left corner of the window.

from kivy.app import App
from kivy.uix.widget import Widget
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import StringProperty

class MyRow(Widget):
    a = StringProperty('a')
    b = StringProperty('b')

    def __init__(self, **kwargs):
        super(MyRow, self).__init__(**kwargs)

class MainScreen(Widget):

    rows = [['a1','b1'],['a2','b2']] #example data

    mainLayout = BoxLayout(orientation='vertical', spacing=5)

    def __init__(self, **kwargs):
        super(MainScreen, self).__init__(**kwargs)

        self.add_widget(self.mainLayout)

        for r in self.rows:
            row_widget = MyRow()

            row_widget.a = r[0]
            row_widget.b = r[1]

            self.mainLayout.add_widget(row_widget)

class MyApp(App):

    def build(self):
        return MainScreen()

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

and this is the kv file:

<MyRow>
    BoxLayout:
        orientation: "horizontal"
        spacing: 30
        Label:
            id: a_label
            text: root.a
        Label:
            id: b_label
            text: root.b

Solution

  • In your sketch it says MyRow is based on an horizontal BoxLayout. But it is not. It is build on widget

    Simply changing

    class MyRow(Widget):
    

    to

    class MyRow(BoxLayout):
    

    will solve your problem.

    enter image description here


    To get spacing right or better I would update your code to the following

    from kivy.app import App
    from kivy.uix.widget import Widget
    from kivy.uix.boxlayout import BoxLayout
    from kivy.properties import StringProperty
    from kivy.base import Builder
    
    
    
    class MyRow(BoxLayout):
        a = StringProperty('a')
        b = StringProperty('b')
    
        def __init__(self, **kwargs):
            super(MyRow, self).__init__(**kwargs)
    
    class MainScreen(BoxLayout):
    
        rows = [['a1','b1'],['a2','b2']]*5 
    
        def __init__(self, **kwargs):
            super(MainScreen, self).__init__(**kwargs)
            self.orientation = "vertical"
    
            for r in self.rows:
                row_widget = MyRow()
    
                row_widget.a = r[0]
                row_widget.b = r[1]
    
                self.add_widget(row_widget)
    
    
    
    class MyApp(App):
    
        def build(self):
            return MainScreen()
    
    if __name__ == '__main__':
        MyApp().run()
    

    and your kv

    <MyRow>:
        orientation: "horizontal"
        spacing: 30
        Label:
            id: a_label
            text: root.a
        Label:
            id: b_label
            text: root.b
    

    which gives you enter image description here


    To inherit from a Boxlayot in python use class Row(BoxLayout): in kv file use <Row@BoxLayout>: