KeyError在kivy中停止App

时间:2014-05-21 16:50:11

标签: python kivy

我试图获得一个我已经建立的应用程序停止某个点,并在停止时运行清理程序。这似乎应该很容易,但我一直遇到错误,而且我无法找到解决方案。

我使用的是kivy 1.8.0和Python 3.3。为了方便起见,我修改了kivy文档中的一些代码,因为我的代码基于相同的框架,并且两者都给出了完全相同的错误:

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.screenmanager import ScreenManager, Screen    
# Create both screens. Please note the root.manager.current: this is how
# you can control the ScreenManager from kv. Each screen has by default a
# property manager that gives you the instance of the ScreenManager used.
Builder.load_string("""
<MenuScreen>:
    BoxLayout:
        Button:
            text: 'Goto settings'
            on_press: root.manager.current = 'settings'
        Button:
            text: 'Quit'
            on_press: root.exit()

<SettingsScreen>:
    BoxLayout:
        Button:
            text: 'My settings button'
        Button:
            text: 'Back to menu'
            on_press: root.manager.current = 'menu'    
""")

# Declare both screens
class MenuScreen(Screen):
    def exit(self):
        App.stop(self)


class SettingsScreen(Screen):
    pass     

# Create the screen manager
sm = ScreenManager()
sm.add_widget(MenuScreen(name='menu'))
sm.add_widget(SettingsScreen(name='settings'))

class TestApp(App):

    def build(self):
        return sm

    def on_stop(self):
        print('leaving now') # this is where I'd want to run the end of program procedure

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

当我运行此命令并单击Quit按钮时,出现以下错误:

builtins.KeyError: 'on_stop'

我还应该注意,如果我在on_stop中注释掉class TestApp功能,则错误仍然存​​在。知道出了什么问题吗?

2 个答案:

答案 0 :(得分:3)

您正在将MenuScreen的实例传递给App.stop(),这会导致您的错误,因为它需要App个实例。您可以检索正在运行的应用并将其停止:

class MenuScreen(Screen):
    def exit(self):
        App.get_running_app().stop()

答案 1 :(得分:0)

以下是您的问题的解决方案:

# Declare both screens
class MenuScreen(Screen):
    def exit(self):
        self.manager.app.stop()

class TestApp(App):

    def build(self):
        # Create the screen manager
        sm = ScreenManager()
        # monkey patch the screen manager instance to add the app
        sm.app = self
        sm.add_widget(MenuScreen(name='menu'))
        sm.add_widget(SettingsScreen(name='settings'))
        return sm

虽然我不认为这是你的问题的规范解决方案,因为它涉及猴子修补。

但错误的是,您要调用的stop()方法只存在于应用实例中,虽然您处理它的方式,但您无法访问正在运行的应用实例,因为它是在需要它的代码之后声明的。

因此,解决方案是在构建方法中移动ScreenManager构建。我认为我的解决方案不是一个好的设计:我基本上通过monkeypatching实例向ScreenManager添加一个成员,给它一个指向App的链接实例

在那里你可以调用close()函数,并优雅地关闭你的应用程序。