循环创建自定义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
原因分析
- 嵌套布局未填充父容器:在
NewFloatLayout的KV定义中嵌套了额外的FloatLayout绘制背景,但该嵌套布局未设置size_hint: 1, 1,无法填充NewFloatLayout的全部区域,背景仅在嵌套布局默认的100x100像素区域显示。 - Canvas指令绑定异常:Kivy会复用同一图片资源的纹理,但嵌套布局的Canvas指令未与每个
NewFloatLayout实例的尺寸、位置正确绑定,最终只有最后一个实例的背景纹理能被正确渲染。 - 拼写错误干扰布局: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
相关产品推荐
相关产品推荐

