在Flet待办清单应用中使用page.client_storage时遇循环引用等错误
Flet待办清单任务保存问题修复
问题表现
- 添加第二个任务时触发报错:
Exception in thread Thread-24 (add_clicked): ValueError: Circular reference detected - 应用重启后报错:
'dict' object has no attribute '_build_add_commands' - 仅能成功添加1个任务,添加第二个任务时立即触发错误。
问题根源
直接将Flet的UI控件(如ft.Row、ft.Checkbox)存入page.client_storage会导致两个问题:
- UI控件内部存在循环引用属性,序列化存储时触发循环引用错误;
- 从存储中读取的是控件的字典序列化结果,并非真正的Flet控件对象,无法直接添加到页面。
修复方案
改为存储任务的纯数据(任务文本、复选框状态),而非UI控件。重启应用时,根据存储的数据重新生成对应的UI控件。
修改后的完整代码
import flet as ft def main(page: ft.Page): page.window_width = 400 page.window_height = 600 page.bgcolor = "#141414" page.window_center() rows = list() # 用于存储任务数据(而非UI控件) rows_data = list() # 顶部导航栏 page.appbar = ft.AppBar( bgcolor="#303030", leading=ft.Icon(ft.icons.CHECKLIST), title=ft.Text("Tareas", font_family="Roboto") ) def create_task_row(task_text, is_checked=False): """根据任务数据创建UI行""" def clear(e): # 从数据列表和UI列表中移除对应项 for idx, data in enumerate(rows_data): if data["text"] == task_text: rows_data.pop(idx) break rows.remove(row) # 更新存储 page.client_storage.set("tasks_data", rows_data) page.update() checkbox = ft.Checkbox(value=is_checked) task = ft.Text(value=task_text, width=258) remove = ft.IconButton( icon="remove_circle", icon_size="32", icon_color="#D05050", on_click=clear ) row = ft.Row(controls=[checkbox, task, remove]) rows.append(row) return row def add_clicked(e): if new_task.value.strip() != "": # 创建任务数据并存储 task_data = {"text": new_task.value.strip(), "checked": False} rows_data.append(task_data) page.client_storage.set("tasks_data", rows_data) # 创建UI行并添加到页面 row = create_task_row(new_task.value.strip()) task_container.controls.append(row) # 清空输入框并更新页面 new_task.value = "" new_task.update() page.update() def clearall(e): rows.clear() rows_data.clear() task_container.controls.clear() page.client_storage.remove("tasks_data") page.update() # 任务输入框 new_task = ft.TextField(hint_text="Agregar tarea", width=300) # 添加任务行 page.add(ft.Row([ new_task, ft.FloatingActionButton( icon="add", on_click=add_clicked, bgcolor="#4B90BE", scale=0.95 ) ])) # 清空所有任务按钮 page.add(ft.FloatingActionButton( icon=ft.icons.CLEANING_SERVICES_ROUNDED, on_click=clearall, bgcolor="#4B90BE", scale=0.95 )) # 用于容纳任务行的容器 task_container = ft.Column() page.add(task_container) # 从存储加载保存的任务数据并重建UI saved_tasks_data = page.client_storage.get("tasks_data") or [] rows_data.extend(saved_tasks_data) for task_data in saved_tasks_data: row = create_task_row(task_data["text"], task_data["checked"]) task_container.controls.append(row) page.update() ft.app(target=main)
关键修改点
- 新增
rows_data列表存储任务的纯数据(字典格式,包含text和checked字段); - 抽离
create_task_row函数,统一处理任务UI行的创建和删除逻辑; - 存储和读取时操作的是任务数据而非UI控件;
- 重启应用时,根据存储的数据重新生成UI控件并添加到页面;
- 删除任务时同步更新数据列表和存储,确保数据一致性。
内容的提问来源于stack exchange,提问作者Artis Wize
相关产品推荐
相关产品推荐

