了解 Kivy 的创建顺序,更改根小部件会导致崩溃
Understand Kivy order-of-creation, changing root widget results in crash
使用 Screenmanager 作为根小部件,我有一些简单的代码来(可选)显示 Splashscreen,然后是 Mainscreen。它工作正常。但我想改变它,所以我有一个 Boxlayout 作为根小部件 insted(所以我可以在 ScreenManager 上方显示一个永远存在的状态栏)。但是,当我添加 Boxlayout 时,它崩溃了,我怀疑是由于我无法理解的创建顺序问题。
此代码有效:
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
但是,如果我尝试添加一个 BoxWidget 作为 ScreenManager 的父级,只有当我允许显示 SplashScreen 时它才会工作,但是如果我设置 SHOW_SPLASH_SCREEN=False
,那么它将在第 self.current = 'screen_main'
行出现以下错误:
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)
我添加了一些调试,我可以看到创建了“screen_main”在这个错误发生之前 - 所以我怀疑可能已经创建了 Screen,但没有但实际添加到 ScreenManager?也许这就是错误的原因?如果是这样,我该如何解决?
这里是导致崩溃的代码:(现在 MasterBoxLayout 是新的根节点)
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也是一样,只是多了一个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
编辑:请注意,我是 Kivy 的新手,如果对我这样做的方式有任何一般性评论......以及对更好方法的建议,我们将不胜感激。
问题是您在 MainScreenManager
的 __init__()
方法中执行此操作。此时,Screens
尚未创建。您可以将该逻辑移动到 on_kv_post()
方法中,这样在执行 kv
规则之前代码不会 运行:
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
使用 Screenmanager 作为根小部件,我有一些简单的代码来(可选)显示 Splashscreen,然后是 Mainscreen。它工作正常。但我想改变它,所以我有一个 Boxlayout 作为根小部件 insted(所以我可以在 ScreenManager 上方显示一个永远存在的状态栏)。但是,当我添加 Boxlayout 时,它崩溃了,我怀疑是由于我无法理解的创建顺序问题。
此代码有效:
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
但是,如果我尝试添加一个 BoxWidget 作为 ScreenManager 的父级,只有当我允许显示 SplashScreen 时它才会工作,但是如果我设置 SHOW_SPLASH_SCREEN=False
,那么它将在第 self.current = 'screen_main'
行出现以下错误:
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)
我添加了一些调试,我可以看到创建了“screen_main”在这个错误发生之前 - 所以我怀疑可能已经创建了 Screen,但没有但实际添加到 ScreenManager?也许这就是错误的原因?如果是这样,我该如何解决?
这里是导致崩溃的代码:(现在 MasterBoxLayout 是新的根节点)
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也是一样,只是多了一个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
编辑:请注意,我是 Kivy 的新手,如果对我这样做的方式有任何一般性评论......以及对更好方法的建议,我们将不胜感激。
问题是您在 MainScreenManager
的 __init__()
方法中执行此操作。此时,Screens
尚未创建。您可以将该逻辑移动到 on_kv_post()
方法中,这样在执行 kv
规则之前代码不会 运行:
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