Reputation: 31597
I have a Kivy Widget
called MainPage
that has a child widget. These child widget needs to have access to the same message dispatcher (has nothing to do with Kivy's EventDispatcher
) as its parent:
class MainPage(Widget):
def __init__(self, dispatcher):
self.child = ChildWidget(dispatcher)
self.add_widget(child1)
Inside the .kv
file I defined the visual properties of <ChildWidget>
, but I have not specified its position inside <MainPage>
. I would like <MainPage>
to specify how its children are supposed to be positioned. Is something like this possible?
<ChildWidget>:
...
<MainPage>:
self.child:
pos: (10, 10)
Upvotes: 1
Views: 3004
Reputation: 19037
If your goal of positioning is not too complicated, a RelativeLayout
might be enough.
class MainPage(RelativeLayout):
def __init__(self, dispatcher, **kwargs):
super(MainPage, self).__init__(**kwargs)
self.child = ChildWidget(dispatcher, pos=(10,10))
self.add_widget(self.child)
The RelativeLayout
(and in general any layout - except FloatLayout which keeps the absolute positioning) keeps the children update to the position of the parent. All the layouts are also widgets so you should be safe.
<ChildWidget>:
size_hint: .1, .05
text: "press me"
on_press: self.parent.pos = (200,200)
<MainPage>:
pos: 400,400
Here is the complete code I tried:
from kivy.app import App
from kivy.lang import Builder
from kivy.uix.relativelayout import RelativeLayout
from kivy.uix.button import Button
Builder.load_string("""
<ChildWidget>:
size_hint: .1, .05
text: "press me"
on_press: self.parent.pos = (200,200)
<MainPage>:
pos: 400,400
""")
class Dispatcher():
pass
class ChildWidget(Button):
def __init__(self, dispatcher, **kwargs):
super(ChildWidget, self).__init__(**kwargs)
self.dispatcher = dispatcher
class MainPage(RelativeLayout):
def __init__(self, dispatcher, **kwargs):
super(MainPage, self).__init__(**kwargs)
self.child = ChildWidget(dispatcher, pos=(10,10))
self.add_widget(self.child)
class TestApp(App):
def build(self):
dispatcher = Widget()
return MainPage(dispatcher)
if __name__ == '__main__':
TestApp().run()
Upvotes: 1
Reputation: 4182
Assuming ChildWidget is still a Kivy Widget (inherited from Widget or a subclass of it).
[simple way using kv]
if you wanted the child to control where it is positioned inside it's parent you could do::
<ChildWidget>
pos: (self.parent.x + 10, self.parent.y + 10) if self.parent else (100, 100)
for controlling the children's position one could do::
<MainPage>
on_children:
# reposition children
root.reposition_children(args[1])
on_size:
# reposition children when parents size changes
root.reposition_children(self.children)
on_pos:
# reposition children when widgets size changes
root.reposition_children(self.children)
in your .py
class MainPage(Widget):
...
...
def reposition_children(self, children):
for child in children:
child.pos = x, y
child.size = d, e
[More elaborate and complete way]
What you essentially seem to want is your Main Widget to behave like a Layout. This link is to the code which also includes the inline docs. The code itself is a abstract class that gives you a guide-line on how to structure/fashion your layout.
You should inherit from the Layout class and do your widget positioning in do_layout, call it through self.trigger_layout(this way positioning of the widgets is delayed till just before they need to be displayed on screen and trigger makes sure that the function is not called multiple times per frame).
You should bind trigger_layout with properties like children, size, pos... so that do_layout
is re-triggered whenever these properties change.
Upvotes: 1