Using a Screenmanager as the root widget, I have some simple code to (optionaly) display a Splashscreen, then the Mainscreen. It works fine. But I would like to alter it, so I have a Boxlayout as the root widget insted (so I can display an ever-present status-bar, above the ScreenManager). However when I add the Boxlayout, it crashes, I suspect due to an order-of-creation issue that is beyond my understanding.
This code works:
class MainScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MainScreenManager, self).__init__(**kwargs)
if not SHOW_SPLASH_SCREEN
self.transition = NoTransition()
self.current = 'screen_main'
self.transition = FadeTransition()
else:
#close the splash screen after 3 seconds
Clock.schedule_once(partial(self.changescreen, 'screen_main'),3)
def changescreen(self, newscreen, *largs):
self.current = newscreen
class Screen_Splash(Screen):
pass
class Screen_Main(Screen):
pass
class TestApp(App):
def build(self):
mainprogram=MainScreenManager()
return mainprogram
if __name__ == '__main__':
TestApp().run()
test.kv
<MainScreenManager>:
id: MainScreenManager
Screen_Splash:
Screen_Main:
<Screen_Splash>:
name: 'screen_splash'
FloatLayout:
Image:
source: 'resources/splashscreen.png'
keep_ratio: True
<Screen_Main>:
name: 'screen_main'
Image:
source: 'resources/1_mainscreen.png'
keep_ratio: True
However, if I try and add a BoxWidget as the parent of the ScreenManager, it will work ONLY if I allow the SplashScreen to be shown, but if I set SHOW_SPLASH_SCREEN=False
, then it will crash on the line self.current = 'screen_main'
with the following error:
self.current = 'screen_main'
File "kivy/properties.pyx", line 520, in kivy.properties.Property.__set__
File "kivy/properties.pyx", line 567, in kivy.properties.Property.set
File "kivy/properties.pyx", line 606, in kivy.properties.Property._dispatch
File "kivy/_event.pyx", line 1307, in kivy._event.EventObservers.dispatch
File "kivy/_event.pyx", line 1213, in kivy._event.EventObservers._dispatch
File "/usr/lib/python3/dist-packages/kivy/uix/screenmanager.py", line 1052, in on_current
screen = self.get_screen(value)
File "/usr/lib/python3/dist-packages/kivy/uix/screenmanager.py", line 1078, in get_screen
raise ScreenManagerException('No Screen with name "%s".' % name)
I added some debugs, I can see that "screen_main" is created before this error occurs - so I suspect maybe that Screen has been created, but not yet actually added to the ScreenManager? Perhaps that is the cause of the bug? If so, how would I fix that?
Here is the code that causes the crash: (now MasterBoxLayout is the new root node)
class MasterBoxLayout(BoxLayout):
#this is now the new Root Node
pass
class MainScreenManager(ScreenManager):
def __init__(self, **kwargs):
super(MainScreenManager, self).__init__(**kwargs)
if not SHOW_SPLASH_SCREEN
self.transition = NoTransition()
self.current = 'screen_main'
self.transition = FadeTransition()
else:
Clock.schedule_once(partial(self.changescreen, 'screen_main'),3)
def changescreen(self, newscreen, *largs):
self.current = newscreen
class Screen_Splash(Screen):
pass
class Screen_Main(Screen):
pass
class TestApp(App):
def build(self):
mainprogram=MasterBoxLayout()
return mainprogram
if __name__ == '__main__':
TestApp().run()
test.ky is the same, except for the addition of a BoxLayout:
<MasterBoxLayout>:
#this should be the new root of the tree
orientation: 'vertical'
MainScreenManager:
<MainScreenManager>:
id: MainScreenManager
Screen_Splash:
Screen_Main:
<Screen_Splash>:
name: 'screen_splash'
FloatLayout:
Image:
source: 'resources/splashscreen.png'
keep_ratio: True
<Screen_Main>:
name: 'screen_main'
Image:
source: 'resources/1_mainscreen.png'
keep_ratio: True
EDIT: Note, I am new to Kivy, if there are any general comments on the way I am doing this...and suggestions for a better method, that would be greatfully received.
CodePudding user response:
The problem is that you are doing this in the __init__()
method of your MainScreenManager
. At that point, the Screens
have not yet been created. You can just move that logic into an on_kv_post()
method, so that the code is not run until the kv
rules are executed:
class MainScreenManager(ScreenManager):
def on_kv_post(self, base_widget):
if not SHOW_SPLASH_SCREEN:
self.transition = NoTransition()
self.current = 'screen_main'
self.transition = FadeTransition()
else:
Clock.schedule_once(partial(self.changescreen, 'screen_main'), 3)
def changescreen(self, newscreen, *largs):
self.current = newscreen