Reputation: 79
If I have a dynamically defined class such as this:
<Foo@BoxLayout>:
orientation: "vertical"
...some other child widgets...
BoxLayout:
id: target
orientation: "horizontal"
...other children...
How do I create a class that inherits from this, with the only change being an additional widget added to the BoxLayout
with id: target
?
I attempted to change the dynamic classes into rules and define the classes in the python:
class Foo(BoxLayout):
pass
class EditedFoo(Foo):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ids["target"].add_widget(<the widget I want to add>, index=0)
however ids was empty from the __init__
function (and from the on_parent
function).
Is there any way to do this without redefining the whole class?
Edit:
from kivy.app import App
from kivy.lang.builder import Builder
from kivy.uix.button import Button
from kivy.uix.boxlayout import BoxLayout
kv = """
BoxLayout:
EditedFoo:
<Foo>:
orientation: "vertical"
BoxLayout:
id: target
orientation: "horizontal"
"""
class TestApp(App):
def build(self):
return Builder.load_string(kv)
class Foo(BoxLayout):
pass
class EditedFoo(Foo):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.ids["target"].add_widget(Button(text="hello"), index=0)
TestApp().run()
Here is a complete verified example of it not working
Upvotes: 2
Views: 1332
Reputation: 243887
The .kv code implements the class created in Python so it is understood that it will be added after the constructor finishes executing, and consequently the ids will be empty in the constructor, a trick is to use Clock that will call a function a moment after rendering the whole window since at that moment the ids will not be empty:
# ...
from kivy.clock import Clock
# ...
class EditedFoo(Foo):
def __init__(self, **kwargs):
super().__init__(**kwargs)
Clock.schedule_once(self.callback)
def callback(self, *args):
self.ids["target"].add_widget(Button(text="hello"), index=0)
Upvotes: 1
Reputation: 596
The codes in .kv
file get initialized after the Python codes are executed.
Therefore, your EditedFoo(Foo)
will inherit the Foo(BoxLayout)
from the Python codes first, then Foo
in .kv
file will be re-declared.
Best way is to put initial attributes of Foo(BoxLayout)
in Python codes, then inherit Foo
in .kv
such as <EditedFoo@Foo>
For example,
In .py
:
class Foo(BoxLayout):
greeting = "hi"
In .kv
:
<EditedFoo@Foo>
greeting: "Goodbye World"
Foo:
id: root_foo
Button:
text: root_foo.greeting
EditedFoo:
id: foo1
Label:
text: foo1.greeting
EditedFoo:
id: foo2
greeting: "Hello Another World"
Button:
text: foo2.greeting
In this way, you can use EditedFoo
class in .kv
inherited from Foo
.
Upvotes: 2