I have a Kivy app where I am injecting a widget as a dependency to the main app. The injected widget has the wrong layout (that was defined in the .kv file). Here are the following files:
Layout is defined using a kv file
# minimal_example/test.kv
<TestAppLayout>
CustomButton:
text: 'Custom Button'
<CustomButton>
text: 'This is a custom button'
background_color: (0.5, 0.5, 0.5, 1)
font_size: 25
Custom widgets are defined in a separate file. This is because I wanted to separate out my files.
# minimal_example/custom_widgets.py
from kivy.uix.button import Button
class CustomButton(Button):
def __init__(self, **kwargs):
super().__init__(**kwargs)
CONSTANT = CustomButton(text='Constant')
When constructing the main app, a CustomButton is injected in as a dependency. But the injected CustomButton has the wrong layout.
# minimal_example/app_with_kv.py
from kivy.app import App
from kivy.uix.boxlayout import BoxLayout
from minimal_example.custom_widgets import CustomButton, CONSTANT
class TestAppLayout(BoxLayout):
def __init__(self, custom_button: CustomButton, **kwargs):
super().__init__(**kwargs)
self.add_widget(CustomButton(text='Added dynamically')) # This has the proper layout
self.add_widget(custom_button) # This does not
class TestApp(App):
def __init__(self, custom_button: CustomButton, **kwargs):
super().__init__(**kwargs)
self._custom_button = custom_button
def build(self):
return TestAppLayout(self._custom_button)
if __name__ == '__main__':
TestApp(CONSTANT).run()
The injected widget has the wrong layout. What has gone wrong here & how can I achieve the correct layout using this dependency injection pattern?
The problem is that you are building the CONSTANT in custom_widgets.py before the test.kv is loaded. The App class automatically loads a correctly named .kv file (like test.kv in your case), and this is loaded in the build() method. There are several ways to fix this.
One is to simply remove the CONSTANT definition from custom_widgets.py and add it into the build() method. This requires some restructuring of your code.
Another way is to force the loading of the test.kv earlier. To do this, you must rename the test.kv file to avoid duplicate loading. For example, rename it to test1.kv, then add:
Builder.load_file('minimal_example/test1.kv')
just before the import of the custom_widgets.py file.