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

Kivy GridLayout首次加载后无法添加/移除组件问题求助

问题与解决方案

问题

尝试清空GridLayoutExample组件并添加新内容,但第二次进入该布局时,无法添加或移除任何组件。调用self.clear_widgets()无效果,二次进入时添加按钮也失败,推测操作的不是当前显示的GUI实例。

原因

  1. 当前代码中,kies_maand和kies_jaar方法仅返回新的GridLayoutExample实例,但未替换界面上已存在的旧实例,界面始终显示初始创建的实例,新实例从未被渲染。
  2. 滥用全局变量管理年份、月份状态,导致状态更新与界面实例不匹配。
  3. GridLayoutExample初始化时调用self.clear_widgets()无意义,初始化时组件本就是空的。

解决方案

核心思路:复用已有的GridLayoutExample实例,通过方法更新其内容,而非创建新实例。

修改后的Python代码

from kivymd.app import MDApp
from kivy.uix.button import Button
from kivy.uix.label import Label
from kivy.uix.gridlayout import GridLayout
from kivy.uix.stacklayout import StackLayout
from calendar import monthrange
import calendar
import datetime


class GridLayoutExample(GridLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        self.year = datetime.datetime.now().year
        self.month_int = datetime.datetime.now().month
        self.weekheader = str(calendar.weekheader(3))
        self.days = self.weekheader.split(" ")
        self.days_length = len(self.days)
        self.build_calendar()

    def build_calendar(self):
        # 清空现有组件与ids字典
        self.clear_widgets()
        self.ids.clear()
        
        num_days = monthrange(self.year, self.month_int)[1]
        month = calendar.monthcalendar(self.year, self.month_int)
        start_day = month[0].count(0)
        
        # 添加星期表头
        for j in range(self.days_length):
            label1 = Label(text=self.days[j], color=(0, 0, 0, 1))
            self.add_widget(label1)
        
        # 添加月初空白占位
        for g in range(start_day):
            label2 = Label()
            self.add_widget(label2)
        
        # 添加日期按钮
        for i in range(num_days):
            day_str = str(i + 1)
            button = Button(text=day_str)
            button_id = f"{day_str}-{self.month_int}-{self.year}"
            button.my_id = button_id
            self.ids[button_id] = button
            self.add_widget(button)

    def update_calendar(self, year, month):
        self.year = year
        self.month_int = month
        self.build_calendar()


class LayoutExample(StackLayout):
    def __init__(self, **kwargs):
        super().__init__(**kwargs)
        for l in range(10):
            label4 = Label(text="zeer plezant \n \n \n ha", size=self.size, color=(0, 0, 0, 1), size_hint=(None, None))
            self.add_widget(label4)
            button = Button(text="wijzig", size_hint=(1, None), size=(100, 60))
            self.add_widget(button)
            button = Button(text="verwijder", size_hint=(1, None), size=(100, 60))
            self.add_widget(button)


class drop(MDApp):
    def build(self):
        self.current_year = datetime.datetime.now().year
        self.current_month = datetime.datetime.now().month
        self.stryear = str(self.current_year)
        self.strmonth_int = str(self.current_month)

    def kies_maand(self, text):
        self.current_month = int(text)
        # 通过id获取界面上的GridLayoutExample实例
        grid = self.root.children[0].ids.calendar_grid
        grid.update_calendar(self.current_year, self.current_month)
        # 更新Spinner显示
        self.root.children[0].ids.month_spinner.text = text

    def kies_jaar(self, text):
        self.current_year = int(text)
        grid = self.root.children[0].ids.calendar_grid
        grid.update_calendar(self.current_year, self.current_month)
        self.root.children[0].ids.year_spinner.text = text


drop().run()

修改后的Kivy代码

#:kivy 1.0
PageLayoutExample:

<PageLayoutExample@PageLayout>:
    Gridspin:
    GridLayouttest:


<ScrollViewExample@ScrollView>:
    size: root.width, root.height
    LayoutExample:


<GridLayouttest@GridLayout>:
    rows: 3
    ScrollViewExample:
    TextInput:
        hint_text:'taak toevoegen'
        size_hint:(1, None) 
        height: 60
    Button:
        text:'toevoegen'
        size_hint:(1, None) 
        height: 60


<Gridspin@GridLayout>:
    rows: 2
    GridLayout:
        height: 60
        size_hint: 1, None
        cols: 2
        Spinner:
            id: month_spinner
            height: 60
            size_hint: 1, None
            text: app.strmonth_int
            values: ['1', '2', '3', '4']
            on_text: app.kies_maand(self.text)
        Spinner:
            id: year_spinner
            height: 60
            size_hint: 1, None
            text: app.stryear
            values: ['2018', '2019', '2020', '2021']
            on_text: app.kies_jaar(self.text)
    GridLayoutExample:
        id: calendar_grid  # 添加id用于获取实例


<GridLayoutExample>:
    cols: 7
    orientation: "lr-tb"
    size: root.minimum_width, root.minimum_height
    padding: ("20dp", "20dp", "20dp", "20dp")


<LayoutExample>:
    orientation: "lr-tb"
    size_hint: 1, None
    height: self.minimum_height
    width: self.width
    canvas.before:
        Color:
            rgba: 1, 1, 1, 1
        Rectangle:
            size: self.width, self.minimum_height
            pos: self.pos

关键修改点

  1. 重构GridLayoutExample:新增build_calendar方法负责构建日历组件,update_calendar方法更新年份月份后重新构建,实现实例复用。
  2. 移除全局变量:改用类实例属性管理年份、月份状态,避免状态混乱。
  3. 布局添加id:给GridLayoutExample和Spinner添加id,确保Python代码能精准获取当前显示的界面实例。
  4. 更新逻辑调整:App类中不再返回新实例,而是直接调用已有实例的update_calendar方法,操作的始终是界面上显示的组件。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.10 23:05:35