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

Kivy中Screen的__init__方法访问ScreenManager引发AttributeError求助

问题分析与解决方案

错误根源

你遇到的AttributeError: 'NoneType' object has no attribute 'add_widget'确实是因为Screen还未被添加到ScreenManager时,self.manager属性为None:

  1. 初始__init__方法执行时,Screen还没被关联到ScreenManager,直接调用self.manager.add_widget自然报错。
  2. 后续修改中,你在MainApp里先调用list_view_screen.load_tasks,再把Screen添加到ScreenManager,此时self.manager仍未被赋值,所以打印self.parent为None,报错依旧。
  3. 循环中使用lambda绑定事件时还存在变量捕获问题——最终所有列表项的点击事件都会指向最后一个item的文本,这是你后续可能遇到的隐性bug。

解决方案

方案一:调整load_tasks的调用时机

将load_tasks的调用放到Screen被添加到ScreenManager之后,此时self.manager已正常赋值:

修改MainApp的build方法

class MainApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = "Dark"
        Builder.load_file("styling.kv")
        sm = ScreenManager()
        list_view_screen = ToDoListView(name = "ListView")
        # 先把Screen添加到ScreenManager
        sm.add_widget(list_view_screen)
        # 此时self.manager已可用,再调用加载逻辑
        list_view_screen.load_tasks(list_view_screen.loaded_items)
        return sm

修正load_tasks方法

修复笔误并解决lambda变量捕获问题:

def load_tasks(self, loaded_objects):
    for i in loaded_objects:
        todo_page = ToDoListPage(name=str(i.text))
        self.manager.add_widget(todo_page)
        # 使用默认参数固定当前item的文本,避免循环变量捕获问题
        i.bind(on_release=lambda x, item_text=i.text: self.change_screen(item_text))

方案二:使用Screen生命周期事件(更符合Kivy设计)

利用Screen的on_pre_enter事件(该事件在Screen被添加到ScreenManager且即将显示时触发),自动执行初始化逻辑,无需手动调用load_tasks:

修改ToDoListView类

def __init__(self, **kw):
    super().__init__(**kw)
    json_data_object = JsonData("data.json")
    self.loaded_items = []
    # 先只添加列表项到MDList,不处理页面绑定
    for i in json_data_object.data["lists"]:
        loaded_object = ListItemWithoutCheckbox(text="[b]" + i["list_name"] + "[/b]")
        self.ids["Container"].add_widget(loaded_object)
        self.loaded_items.append(loaded_object)

def on_pre_enter(self, *args):
    # 此事件触发时,self.manager已被正确赋值
    for i in self.loaded_items:
        todo_page = ToDoListPage(name=str(i.text))
        self.manager.add_widget(todo_page)
        i.bind(on_release=lambda x, item_text=i.text: self.change_screen(item_text))

简化MainApp的build方法

class MainApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = "Dark"
        Builder.load_file("styling.kv")
        sm = ScreenManager()
        sm.add_widget(ToDoListView(name = "ListView"))
        return sm

补充:确保change_screen方法正确实现

最后确认你的页面跳转方法逻辑正确:

def change_screen(self, screen_name):
    self.manager.current = screen_name

内容的提问来源于stack exchange,提问作者Dean Williams

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.31 01:57:38