如何在Kivy的App类与ScreenManager的多Screen间共享变量?
问题描述
我正在开发一个简单应用,需要在初始页面获取用户名。我在testApp类中定义了一个变量,希望在继承Screen的其他类中对其进行读写操作。尝试了self.root、self.parent、self.manager等多种方式,但都无法实现。我本身不太擅长面向对象编程,之前的相关问题都已解决,现在学习ScreenManager时遇到了这个难题。
现有代码
main.py
from kivy.app import App from kivy.lang import Builder from kivy.uix.screenmanager import ScreenManager,Screen from kivy.properties import Clock from kivy.properties import StringProperty class MainMenu(Screen): pass class secondMenu(Screen): def __init__(self,**kwargs): super(secondMenu, self).__init__(**kwargs) def set_name(self,field): self.manager.parent.name = field.text class thirdMenu(Screen): def __init__(self,**kwargs): super(thirdMenu, self).__init__(**kwargs) Clock.schedule_interval(self.update,1/60) def update(self,_): pass class testApp(App): name = StringProperty('') def __init__(self,**kwargs): super(testApp, self).__init__(**kwargs) Clock.schedule_interval(self.update,1/60) def build(self): sm = ScreenManager() sm.add_widget(MainMenu(name='main')) sm.add_widget(secondMenu(name='second')) sm.add_widget(thirdMenu(name='third')) return sm def update(self,dt): pass def on_name(self): print(self.name) if __name__ == '__main__': testApp().run()
kv文件
MainMenu: <MainMenu>: canvas.before: Color: rgb:(.3,.6,.7) Rectangle: size: self.size GridLayout: cols: 1 Label: text: 'lading page' color:(.30,.2,.9) Button: text:'go to next page' on_press: root.manager.current = 'second' <secondMenu>: canvas.before: Color: rgb:(.3,.6,.7) Rectangle: size: self.size GridLayout: cols: 1 Label: text: 'enter info' color:(.30,.2,.9) TextInput: id:input_name text:'enter your name' on_text_validate: root.set_name(self) multiline: False Button: text:'go to next page' on_press: root.manager.current = 'third' root.manager.transition.direction = 'up' <thirdMenu>: canvas.before: Color: rgb:(.3,.6,.7) Rectangle: size: self.size GridLayout: cols: 1 Label: id:label_name text: '' color:(.30,.2,.9)
解决方案
通过App.get_running_app()可以直接获取当前运行的testApp实例,从而访问其中定义的name变量,无需依赖self.manager.parent这类错误路径。
修改后的关键代码
- 更新
secondMenu的set_name方法:
def set_name(self, field): App.get_running_app().name = field.text
- 在
thirdMenu中读取并显示用户名,可直接绑定到Label的text属性,无需使用Clock轮询:
修改kv文件中的thirdMenu部分:
<thirdMenu>: canvas.before: Color: rgb:(.3,.6,.7) Rectangle: size: self.size GridLayout: cols: 1 Label: id:label_name text: app.name # 直接绑定到App的name属性 color:(.30,.2,.9)
这样就能实现不同Screen对App类中name变量的读写共享,同时也可以选择使用id来传递数据,但通过App实例共享变量的方式更适合全局状态的管理。
内容的提问来源于stack exchange,提问作者amir_hossain oroujlou
相关产品推荐
相关产品推荐

