user3748883
user3748883

Reputation: 339

Python Kivy Screen manager with predefined Layout doesn't work

My Main class returns a instance of ScreenManager. This ScreenManager has a widget with a Screen class, and I want this Screen class to use a widget which is a Layout that I defined earlier.

When I execute the code, it only show a black screen with no more information. It should show a Button instead.

This is my file minimum.py:

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.app import App

class LayoutWithButton(BoxLayout):

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

class MainScreenApp(Screen):

    def __init__(self, **kwargs):
        super(MainScreenApp, self).__init__(**kwargs)
        button_layout = LayoutWithButton()
        self.add_widget(button_layout)

screen_manager = ScreenManager()
screen_manager.add_widget(MainScreenApp(name='main'))

class TestMainApp(App):

    def build(self):
        return screen_manager

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

And this is my file testmain.kv:

<LayoutWithButton>:
    Button:
        text: 'hello'

Even so, if I replace the line self.add_widget(button_layout) of the class MainScreenApp with the line self.add_widget(Button()) it works well.

What am I doing wrong?

Upvotes: 1

Views: 827

Answers (2)

FJSevilla
FJSevilla

Reputation: 4513

The problem is that kv file is not loaded until TestMainApp is initialized. As you instanciate MainScreenApp before this, the rules defined within the kv have no effect.

A very simple solution is to move instanciation of MainScreenApp to App subclass:

class MainApp(App):

    def build(self):
        screen_manager = ScreenManager()
        screen_manager.add_widget(MainScreenApp(name='main'))
        return screen_manager

You can also force the kv load before instantiating:

from kivy.uix.boxlayout import BoxLayout
from kivy.uix.screenmanager import ScreenManager, Screen
from kivy.lang.builder import Builder
from kivy.app import App


class LayoutWithButton(BoxLayout):
    pass


class MainScreenApp(Screen):

    def __init__(self, **kwargs):
        super(MainScreenApp, self).__init__(**kwargs)
        button_layout = LayoutWithButton()
        self.add_widget(button_layout)

Builder.load_file("testmain.kv")
screen_manager = ScreenManager()
screen_manager.add_widget(MainScreenApp(name='main'))


class TestApp(App):

    def build(self):
        return screen_manager


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

Another option is do everything in your kv:

from kivy.uix.screenmanager import ScreenManager
from kivy.app import App


class RootWidget(ScreenManager):
    pass


class MainTestApp(App):
    def build(self):
        return MainWindow()


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

maintest.kv:

<LayoutWithButton@BoxLayout>:
    Button:
        text: 'hello'

<MainScreenApp@Screen>:
    LayoutWithButton:

<RootWidget>:
    MainScreenApp:
        name: "main"

Upvotes: 4

kuzeyron
kuzeyron

Reputation: 23

From testmain.kv you should remove that < and > from the class name. You only use it when you are styling it and will also be calling it many many times.

Example how your code should look like:

LayoutWithButton:
     Button:
          text: 'hello'

When to use < and >:

<LayoutWithButton>:
      pos_hint: 0, .5
      Button:
          text: 'hello'

BoxLayout:
    LayoutWithButton:
         pos_hint: 0, .5

Good luck!

Upvotes: 1

Related Questions