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

循环创建自定义FloatLayout仅最后一个显示背景的问题排查

问题:自定义FloatLayout组件循环创建实例仅最后一个显示背景图

自定义了NewFloatLayout组件并设置默认背景图,通过循环创建多个该组件实例时,仅最后一个实例能显示背景图,其余均无法显示。

代码片段

Python代码

from kivy.app import App
from kivy.lang import Builder
from kivy.uix.floatlayout import FloatLayout
from kivy.uix.label import Label
from kivymd.app import MDApp
import own_classes


KV = """
<NewFloatLayout>
    FloatLayout:
        canvas.before:
            Rectangle:
                pos: self.pos
                size: self.size
                source: 'icons/events/event_back_panel.png'
"""


class NewFloatLayout(FloatLayout):
    def __init__(self, **kwargs):
        super(NewFloatLayout, self).__init__(**kwargs)


class TestApp(MDApp):
    def build(self):
        self.theme_cls.theme_style = 'Light'
        self.theme_cls.primary_palette = 'BlueGray'
        Builder.load_file("test.kv")
        Builder.load_string(KV)

    def on_start(self):
        events_filling()

def pass_funk():
    pass


def events_filling():
    app = App.get_running_app()
    events_dict = [
        {'date': '2023-02-25', 'date_time': '2023-02-25 05:20:00', 'description': 'pat cat', 'status': 'active', 'time': '05:20:00', 'title': 'pat', 'event_key': '-NP3v5nCWQO-VsastQdA'},
        {'date': '2023-03-18', 'date_time': '2023-03-18 00:29:00', 'description': 'drink beer', 'status': 'active', 'time': '00:29:00', 'title': 'drink beer', 'event_key': '-NQig0z4yKmHs0o2bSe-'},
        {'date': '2023-04-23', 'date_time': '2023-04-23 15:20:00', 'description': 'eat meat', 'status': 'active', 'time': '15:20:00', 'title': 'eat meat', 'event_key': '-NP6a-RDO0nKwH794j_F'}
    ]
    for i in events_dict:
        layout_for_event = NewFloatLayout()
        events_box_layout = app.root.ids['events_layout']

        title = own_classes.LabelButton(text=i['title'], size_hint=(.7, .3),
                                        pos_hint={"top": .95, "right": .8}, color=(.72, .39, 0, 1), halign="left", valign="top",
                                        font_size=16)
        title.bind(size=title.setter('text_size'), on_release=pass_funk)

        description = own_classes.LabelButton(text=i['description'], size_hint=(.7, .4),
                            pos_hint={"top": .65, "right": .8}, halign="left", valign="top", font_size=15)
        description.bind(size=description.setter('text_size'), on_release=pass_funk)

        date = Label(text=i['date'], size_hint=(.4, .3), color=(.6, .6, .6, 1),
                     pos_hint={"top": .3, "left": .5})
        time = Label(text=i['time'], size_hint=(.4, .3), color=(.6, .6, .6, 1),
                     pos_hint={"top": .3, "right": .8})

        copy_button = own_classes.ImageButton(source="icons/events/copy.png", size_hint=(.25, .3),
                                              pos_hint={"top": .95, "right": 1})
        copy_button.bind(on_release=pass_funk)

        done_button = own_classes.ImageButton(source="icons/events/done.png", size_hint=(.25, .3),
                                              pos_hint={"top": .65, "right": 1})
        done_button.bind(on_release=pass_funk)

        delete_button = own_classes.ImageButton(source="icons/events/delete.png", size_hint=(.25, .3),
                                                pos_hint={"top": .35, "right": 1})
        delete_button.bind(on_release=pass_funk)

        layout_for_event.add_widget(title)
        layout_for_event.add_widget(description)
        layout_for_event.add_widget(date)
        layout_for_event.add_widget(time)
        layout_for_event.add_widget(copy_button)
        layout_for_event.add_widget(done_button)
        layout_for_event.add_widget(delete_button)
        events_box_layout.add_widget(layout_for_event)


TestApp().run()

KV文件(test.kv)

#:import test test

ScrollView:
    pos_hint: {"top": .79, "left": 1}
    size_hint: 1, .79
    GridLayout:
        id: events_layout
        name: "events_layout"
        cols: 1
        size_hint_y: None
        pos_hint: {"top": 1, "left": .8}
        height: self.minimum_height
        row_default_height: '100dp'
        row_fource_default: True

原因分析

  1. 嵌套布局未填充父容器:在NewFloatLayout的KV定义中嵌套了额外的FloatLayout绘制背景,但该嵌套布局未设置size_hint: 1, 1,无法填充NewFloatLayout的全部区域,背景仅在嵌套布局默认的100x100像素区域显示。
  2. Canvas指令绑定异常:Kivy会复用同一图片资源的纹理,但嵌套布局的Canvas指令未与每个NewFloatLayout实例的尺寸、位置正确绑定,最终只有最后一个实例的背景纹理能被正确渲染。
  3. 拼写错误干扰布局:KV文件中row_fource_default是拼写错误,应为row_force_default: True,该错误可能导致行高未正确应用,进一步影响背景显示。

解决方案

1. 修改KV定义,直接在组件自身绘制背景

去掉嵌套的FloatLayout,直接在NewFloatLayout的canvas.before中绘制背景,确保每个实例的背景自动继承父容器的尺寸和位置:

<NewFloatLayout>
    canvas.before:
        Rectangle:
            pos: self.pos
            size: self.size
            source: 'icons/events/event_back_panel.png'

2. 修正KV文件中的拼写错误

将row_fource_default: True改为row_force_default: True,确保GridLayout的行高设置生效:

GridLayout:
    id: events_layout
    name: "events_layout"
    cols: 1
    size_hint_y: None
    pos_hint: {"top": 1, "left": .8}
    height: self.minimum_height
    row_default_height: '100dp'
    row_force_default: True

3. 可选:简化Python代码中的组件初始化

NewFloatLayout的__init__方法无额外逻辑,可直接省略:

class NewFloatLayout(FloatLayout):
    pass

内容的提问来源于stack exchange,提问作者Stanislav Bobovych

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 16:45:01