A widget with a list of widgets

311 views
Skip to first unread message

Yoel Koenka

unread,
May 20, 2015, 11:25:22 AM5/20/15
to kivy-...@googlegroups.com
Hi all,
I've tried to simplify this example as much as possible:

In my app I have Container widgets which holds a list of InnerWidgets, which should be drawn inside it.
I have to add all of them (the containers and their inner widgets) programmatically, so I though __init__ would be a good place to do that:

main.py:
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from kivy.properties import ListProperty

class InnerWidget(BoxLayout):
   
pass

class Container(BoxLayout):
    widgets
= ListProperty([InnerWidget()])
   
   
def __init__(self, **kwargs):
       
super(Container, self).__init__(**kwargs)
       
       
# Add all of the inner widgets in the list
       
for var in self.widgets:
           
self.add_widget(var)

class Test(BoxLayout):
   
def __init__(self, **kwargs):
       
super(Test, self).__init__(**kwargs)
       
self.add_widget(InnerWidget())
       
self.add_widget(Container())

class TestApp(App):
   
def build(self):
       
return Test()

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

test.kv:
<Test>:
    Button:
        text: 'test'
       
<InnerWidget>:
    orientation: 'horizontal'
    Button:
        text: 'inner widget'
               
<Container>:
    orientation: 'vertical'
    Button:
        text: 'container'


If you look at the result, The first 'test' button shows up fine, then the inner widget that was added directly to the Test object shows fine as well.
But the Container object that was added last, only shows its own content (a 'container' button) but not its children's content (an InnerWidget).

I debugged it and saw that when the InnerWidget is added to the Container, the children list of InnerWidget is empty.

I also tried moving the add_widget calls in Container to a function to be called later (when the user presses a button), but this doesn't help.

The only way I found so far is delete the kv layout for InnerWidget and programmatically add its content:
class InnerWidget(BoxLayout):
   
def __init__(self, **kwargs):
       
super(InnerWidget, self).__init__(**kwargs)
       
self.add_widget(Button(text='inner widget'))

But I don't want to do that, it doesn't seem like the Kivy way.
There must be a way for me to use the kv layout.


Am I missing something?
What is the proper way for adding sub widgets programmatically, while using their kv layout?

 Thanks in advance,
Joel

Alexander Taylor

unread,
May 20, 2015, 3:00:40 PM5/20/15
to kivy-...@googlegroups.com
The content of your widgets property is '[InnerWidget()]', but this is evaluated when your file is loaded the first time, which predates the App loading the kv rule for this widget.

There's more than one way to fix this. Personally I'd probably change how you populate the widgets list, e.g. (depending on what you want to do) you could just add InnerWidget rather than an instance. Then you can do 'for var in self.widgets: self.add_widget(widget())'.

Yoel Koenka

unread,
May 20, 2015, 5:37:49 PM5/20/15
to kivy-...@googlegroups.com
Oh now I get it. Thanks for clarifying this!

But I actually can't follow your suggestion as I need to pass many arguments to each InnerWidget.

So what I chose to do is to save the kwargs the InnerWidget got when it was first created, and then used them to create a copy of it after the application has started (overriding __copy__).

This solves the problem, a bit in a hacky way though.
If you have a better idea I'd be very happy to read.

Thanks again!

--
You received this message because you are subscribed to a topic in the Google Groups "Kivy users support" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/kivy-users/LxCUHfnoImw/unsubscribe.
To unsubscribe from this group and all its topics, send an email to kivy-users+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Yoel Koenka

unread,
May 21, 2015, 8:29:21 AM5/21/15
to kivy-...@googlegroups.com
Just a short update (for whoever is interested).
I decided to drop the copy constructor approach, and instead I created a build() method for the Container, to be called after the system is up.
To unsubscribe from this group and all its topics, send an email to kivy-users+unsubscribe@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages