You need to enable JavaScript to run this app. KivyMD用for循环生成MDCard滚动列表 解决已有父组件报错
优惠活动
大模型
产品
解决方案
定价
更多

KivyMD用for循环生成MDCard滚动列表 解决已有父组件报错

核心错误排查
  • 触发*「It has already parent widget」*报错的直接原因:代码在循环外仅初始化了1个AsyncImage实例,循环内重复将同一个实例绑定到多个MDCard上。Kivy的Widget实例仅能归属一个父容器,一旦被添加到组件树后,再次往其他容器添加就会触发该错误。
  • 布局结构不符合ScrollView规则:ScrollView仅能容纳1个直接子组件,直接往ScrollView内的Screen添加多个列表项的写法会导致布局错乱;且Screen组件是专为ScreenManager设计的路由容器,不适合作为滚动列表的承载容器。
  • 类名与KV模板不匹配:KV中定义的是<main>(小写开头),但代码中对应的Screen类是Main(大写开头),会导致模板绑定失效。
修改方案
  • 调整布局结构:把ScrollView内的承载组件换成垂直方向的BoxLayout,用来统一排列所有MDCard列表项。
  • 循环内动态创建组件实例:每个MDCard、每个卡片内的图片/文本都在循环内部初始化,避免复用同一个Widget实例。
  • 修正类名与KV模板的匹配关系:保证KV中定义的模板标签和代码中的类名大小写完全一致。
修改后的可运行代码
from kivymd.app import MDApp
from kivy.lang import Builder
from kivy.core.window import Window
from kivy.uix.screenmanager import Screen
from kivymd.uix.boxlayout import BoxLayout
from kivy.uix.image import AsyncImage
from kivymd.uix.card import MDCard
from kivymd.uix.label import MDLabel

Window.size = (450, 740)

kv = '''
ScreenManager:
    Main:

<Main>:
    name: 'main'
    video_list: video_list
    BoxLayout:
        orientation: 'vertical'
        MDToolbar:
            title: 'Video downloader'

        ScrollView:
            BoxLayout:
                id: video_list
                orientation: 'vertical'
                padding: dp(10)
                spacing: dp(15)
                size_hint_y: None
                # 动态调整高度,适配所有列表项的总高度
                height: self.minimum_height
     '''

class Main(Screen):
    pass

class Ytube(MDApp):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.theme_cls.primary_palette = "Red"
        self.root = Builder.load_string(kv)

    def on_start(self):
        # 获取滚动列表的容器
        list_container = self.root.get_screen('main').ids.video_list
        # 批量生成测试卡片
        for i in range(10):
            # 每个卡片在循环内独立创建,不跨循环复用实例
            card = MDCard(
                orientation='vertical',
                size_hint_y=None,
                height="180dp",
                padding=dp(10),
                spacing=dp(10),
                pos_hint={"center_x": 0.5}
            )
            # 循环内独立创建图片实例
            card.add_widget(AsyncImage(
                source='https://static.hub.91mobiles.com/wp-content/uploads/2020/05/How-to-download-youtube-videos.jpg',
                size_hint_y=0.7
            ))
            # 循环内独立创建文本标签
            card.add_widget(MDLabel(
                text=f'Phishing attacks are SCARY easy to do!! (let me show you!) 第{i+1}条',
                size_hint_y=0.3,
                halign="left",
                valign="middle"
            ))
            list_container.add_widget(card)

    def build(self):
        return self.root

if __name__ == "__main__":
    Ytube().run()
关键优化说明
  • 给承载列表的BoxLayout设置size_hint_y: None和height: self.minimum_height,让容器高度自动适配所有列表项的总高度,保证ScrollView可以正常滚动。
  • 给MDCard设置固定的height和统一的spacing、padding,实现均匀间距的列表布局效果。
  • 删除冗余的手动ScreenManager初始化代码,完全通过KV模板统一管理组件树,避免绑定冲突。
  • 将组件初始化逻辑移到on_start生命周期方法中执行,保证组件树加载完成后再操作id绑定的容器,避免空引用错误。

内容的提问来源于stack exchange,提问作者Rohit Dalal

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.11.05 04:54:03