KivyMD条件切换屏幕报'super' object无__getattr__属性错误
问题根因
你遇到的'super' object has no attribute '__getattr__'报错和标注的切屏代码行无关,核心是几个错误叠加导致的:
self.root指向你在build里返回的ScreenManager实例,而user、password两个输入框的id是定义在login屏幕内部的,不属于ScreenManager的ids字典,跨层级访问不存在的id就会触发这个属性错误,报错位置只是刚好跑到切屏行之前的取值逻辑时触发,你误判了问题点。- build方法里初始屏幕直接设成了
menu,打开APP直接进菜单,根本走不到登录流程。 - kv文件里
<menu>规则头漏了冒号,存在语法错误。 - 你在py里手动实例化ScreenManager、重复给Screen传name参数的写法,和kv里的屏幕规则定义存在重复加载冲突。
修正方案
Kivy/KivyMD完全支持在Python代码里先做认证校验再切屏,所谓“必须在kv的on_release里直接绑定切屏”的说法是错的,只要正确访问组件id、拿到ScreenManager的引用,在任意逻辑节点都可以控制屏幕跳转。
修正后的代码如下:
Teste.py
from kivy.lang import Builder from kivymd.app import MDApp from kivymd.uix.dialog import MDDialog from kivymd.uix.button import MDFlatButton from kivy.uix.screenmanager import ScreenManager, Screen class LoginScreen(Screen): pass class MenuScreen(Screen): pass class TestScreenManager(ScreenManager): pass class LoginApp(MDApp): dialog = None def build(self): self.theme_cls.theme_style = "Light" self.theme_cls.primary_palette = "Indigo" self.theme_cls.accent_palette = "Blue" # 直接加载kv作为根组件,kv里已经定义好ScreenManager和挂载的屏幕 return Builder.load_file('lteste.kv') def dialog_box(self): if not self.dialog: # 先拿到login屏幕实例,再访问它内部的输入框id login_screen = self.root.get_screen('login') self.dialog = MDDialog( title="Log In", text=f"Welcome {login_screen.ids.user.text}!", buttons=[ MDFlatButton( text="Ok", text_color=self.theme_cls.primary_color, on_release=self.close ), ], ) self.dialog.open() def validate_login(self): login_screen = self.root.get_screen('login') username = login_screen.ids.user.text password = login_screen.ids.password.text # 先做账号密码校验,通过后再切屏 if username == '1' and password == '1': self.root.current = "menu" self.dialog_box() def close(self, instance): self.dialog.dismiss() if __name__ == "__main__": LoginApp().run()
lteste.kv
# 根组件为ScreenManager,默认加载第一个挂载的login屏幕 TestScreenManager: LoginScreen: name: "login" MenuScreen: name: "menu" <LoginScreen>: MDCard: size_hint: None, None size: 300, 600 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 65 spacing: 35 orientation: 'vertical' MDIcon: icon: 'account' # 原代码透明度设为0会导致图标完全不可见,修正为不透明 icon_color: 0, 0, 0, 1 halign: 'center' font_size: 180 MDTextFieldRound: id: user icon_left: "account-check" hint_text: "Usuário" foreground_color: 1, 0, 1, 1 size_hint_x: None width: 220 font_size: 20 pos_hint: {"center_x": 0.5} MDTextFieldRound: id: password icon_left: "key-variant" hint_text: "Senha" foreground_color: 1, 0, 1, 1 size_hint_x: None width: 220 font_size: 20 pos_hint: {"center_x": 0.5} password: True MDFillRoundFlatButton: text: "ENTRAR" font_size: 15 pos_hint: {"center_x": 0.5} on_press: app.validate_login() MDFillRoundFlatButton: text: "REGISTRAR-SE" font_size: 15 pos_hint: {"center_x": 0.5} <MenuScreen>: # 原代码此处漏了冒号,属于语法错误 MDCard: size_hint: None, None size: 300, 600 pos_hint: {"center_x": 0.5, "center_y": 0.5} elevation: 10 padding: 65 spacing: 35 orientation: 'vertical' MDRaisedButton: text: "Test"
关键注意点
- Kivy的ids作用域是和所属的根规则绑定的,不要跨层级直接从App.root访问嵌套在子屏幕里的组件id,先通过
get_screen(屏幕名)拿到对应屏幕实例,再访问它内部的ids。 - 不要同时在kv和py里重复实例化ScreenManager、重复添加屏幕组件,避免出现组件加载冲突。
- 切屏逻辑没有强制要求写在kv里,只要能拿到正确的ScreenManager实例,在py里的任意业务逻辑节点都可以修改
current属性实现跳转,完全适配先校验再跳转的场景。
内容的提问来源于stack exchange,提问作者Carlos Jooj
相关产品推荐
相关产品推荐

