You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

多屏幕场景下KivyMD应用中self.root.ids引发属性错误的问题排查求助

解决多屏幕下的AttributeError问题(找不到Chapter id)

你遇到的这个AttributeError确实是因为对self.root.ids的使用有误。你的self.root是ScreenManager实例,而Chapter这个id是定义在BooksScreen内部的MDList组件,直接从ScreenManager的ids里根本找不到它,这就是错误的根源。

下面我会一步步帮你修正问题,同时顺便修复代码里的其他小bug:

核心修改点

  1. 正确获取目标屏幕的组件:要访问BooksScreen里的Chapter列表,得先通过ScreenManager的get_screen()方法拿到BooksScreen的实例,再访问它的ids。
  2. 补充缺失的依赖:Python代码里漏了import os,必须补上才能遍历文件目录。
  3. 修复KV文件语法错误:比如MDList id: Chapter应该写成MDList: id: Chapter,还有部分OneLineIconListItem的语法问题。
  4. 修正播放方法的文本打印:原来的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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.29 11:32:35