多屏幕场景下KivyMD应用中self.root.ids引发属性错误的问题排查求助
解决多屏幕下的AttributeError问题(找不到Chapter id)
你遇到的这个AttributeError确实是因为对self.root.ids的使用有误。你的self.root是ScreenManager实例,而Chapter这个id是定义在BooksScreen内部的MDList组件,直接从ScreenManager的ids里根本找不到它,这就是错误的根源。
下面我会一步步帮你修正问题,同时顺便修复代码里的其他小bug:
核心修改点
- 正确获取目标屏幕的组件:要访问
BooksScreen里的Chapter列表,得先通过ScreenManager的get_screen()方法拿到BooksScreen的实例,再访问它的ids。 - 补充缺失的依赖:Python代码里漏了
import os,必须补上才能遍历文件目录。 - 修复KV文件语法错误:比如
MDList id: Chapter应该写成MDList: id: Chapter,还有部分OneLineIconListItem的语法问题。 - 修正播放方法的文本打印:原来的
print(OneLineListItem.text)是访问类属性,应该获取被点击的列表项实例的文本。
修改后的完整代码
Python代码
from kivymd.app import MDApp from kivymd.uix.list import OneLineListItem from kivy.uix.screenmanager import ScreenManager, Screen from kivymd.uix.button import MDRectangleFlatIconButton, MDFloatingActionButton from kivy.lang import Builder import pygame import os # 补充缺失的导入 pygame.mixer.init() path = "C://abapp3" class BooksScreen(Screen): pass class ChapterScreen(Screen): pass class MainApp(MDApp): def build(self): sm = ScreenManager() sm.add_widget(BooksScreen(name='BooksScreen1')) sm.add_widget(ChapterScreen(name='ChapterScreen1')) return sm def on_start(self): songs = self.load_songs(path) if songs: # 增加判断,避免空列表导致加载失败 pygame.mixer.music.load(songs[0]) def load_songs(self, path_): songs = [] # 先获取BooksScreen的实例 books_screen = self.root.get_screen('BooksScreen1') for filename in os.listdir(path_): if filename.endswith('.wav'): song_path = os.path.join(path_, filename) songs.append(song_path) # 通过books_screen实例访问Chapter列表 books_screen.ids.Chapter.add_widget( OneLineListItem( text=filename[2:], on_release=self.play_song, pos_hint={"center_x": 1, "center_y": 1} ) ) return songs @staticmethod def play_song(*args): pygame.mixer.music.play() # 获取被点击的列表项的文本 if args: print(args[0].text) @staticmethod def stop_song(*args): pygame.mixer.music.stop() print("song stopped") MainApp().run()
KV语言代码
ScreenManager: BooksScreen: name: 'BooksScreen1' ChapterScreen: name: 'ChapterScreen1' <BooksScreen>: NavigationLayout: ScreenManager: Screen: # Front / Main Screen MDBoxLayout: orientation: "vertical" #Toolbar MDToolbar: title: "Chapters" font_style: "Caption" elevation: 8 left_action_items: [['menu', lambda x: nav_drawer.set_state("open")]] Widget: #stop/pause Button MDBoxLayout: orientation:"vertical" Button: text:"Pause" on_press: app.stop_song() BoxLayout: Button: text: 'Goto settings' on_press: root.manager.transition.direction = 'left' root.manager.current = 'ChapterScreen1' # Chapters list/ Play list MDScreen: MDBoxLayout: orientation: "vertical" MDList: id: Chapter #Options menu MDNavigationDrawer: id: nav_drawer MDBoxLayout: orientation: "vertical" padding: "8dp" spacing: "8dp" ScrollView: # Options Menu Options MDList: MDRectangleFlatIconButton: on_press: root.ids.nav_drawer.set_state("close") pos_hint: {"center_x": .5, "center_y": .5} icon: 'arrow-left' line_color: 0, 0, 0, 0 OneLineIconListItem: text: "Options" font_style: "Caption" # Options Menu- About OneLineIconListItem: text: "About" font_style: "Caption" # Options Menu Storage OneLineIconListItem: text: 'Storage' font_style: "Caption" # Options Menu Toolbox OneLineIconListItem: text: 'Choose Voice' font_style: "Caption" # Options Menu About OneLineIconListItem: text: 'About' font_style: "Caption" <ChapterScreen>: BoxLayout: Button: text: 'Back to menu' on_press: root.manager.transition.direction = 'right' root.manager.current = 'BooksScreen1'
额外说明:我还修复了KV里几个容易被忽略的小问题,比如给屏幕明确指定name、补全Pause按钮的组件定义、调整多行语句的格式,这些都能避免不必要的运行错误。
内容的提问来源于stack exchange,提问作者Wil Steve
相关产品推荐
相关产品推荐

