0

0

Flet 应用中利用 page.client_storage 实现数据持久化教程

聖光之護

聖光之護

发布时间:2025-08-06 22:42:01

|

312人浏览过

|

来源于php中文网

原创

flet 应用中利用 page.client_storage 实现数据持久化教程

本教程详细讲解如何在 Flet 应用中使用 page.client_storage 实现数据持久化,以确保用户数据在应用重启后依然存在。我们将深入探讨存储 Flet UI 控件时常见的“循环引用”错误,并提供正确的解决方案:即仅存储可序列化的数据类型(如字符串、数字或由它们组成的列表/字典),而非 Flet 控件对象本身,并通过示例代码演示如何有效管理和加载持久化数据。

1. 理解 Flet 的 page.client_storage

Flet 框架为开发者提供了一个名为 page.client_storage 的机制,用于在客户端(通常是浏览器或桌面应用的本地存储)持久化数据。这类似于 Web 开发中的 localStorage,它允许应用在会话结束后依然保留少量数据,以便在下次启动时恢复。

page.client_storage 是一个简单的键值对存储,其基本操作包括:

  • page.client_storage.set(key, value): 存储一个键值对。value 必须是可序列化的数据类型(字符串、数字、布尔值,或由它们组成的列表/字典)。
  • page.client_storage.get(key): 根据键获取存储的值。
  • page.client_storage.remove(key): 移除指定键的数据。
  • page.client_storage.clear(): 清除所有存储的数据。
  • page.client_storage.get_keys(prefix): 获取所有以指定前缀开头的键。

2. 为什么不能直接存储 Flet 控件?

在尝试使用 page.client_storage 存储 Flet UI 控件(如 ft.Row、ft.Text、ft.Checkbox 等)时,开发者经常会遇到 ValueError: Circular reference detected 或 'dict' object has no attribute '_build_add_commands' 等错误。

这是因为 Flet 控件是复杂的 Python 对象,它们内部包含对其他控件、父控件、事件处理器等的引用。这些复杂的内部结构导致它们无法直接被 JSON 序列化(page.client_storage 在底层通常依赖于 JSON 序列化来存储数据)。当你尝试存储一个包含循环引用的对象时,序列化器会陷入无限循环,从而抛出 Circular reference detected 错误。即使没有循环引用,Flet 控件对象本身也包含许多非数据属性和方法,这些都不是 client_storage 期望存储的简单数据。

核心原则:page.client_storage 应该存储数据,而不是 UI 控件。 你应该存储用户输入的数据(例如,待办事项的文本内容),然后在应用启动时,根据这些存储的数据动态地重建 UI 控件。

3. 实现一个持久化的 To-Do List 应用

我们将基于一个待办事项应用来演示如何正确使用 page.client_storage。

3.1 应用结构概览

我们的 To-Do List 应用将包含:

  • 一个文本输入框用于添加新任务。
  • 一个“添加”按钮。
  • 一个显示所有任务的区域。
  • 一个“清除所有任务”按钮。

3.2 关键实现步骤

  1. 数据存储策略:

    • 不存储 ft.Row 或 ft.Text 对象。
    • 只存储任务的文本内容(字符串)。
    • 为每个任务生成一个唯一的键,例如 t1, t2, t3 等,以便独立存储和检索。我们可以利用一个计数器来实现这一点。
  2. 添加任务与存储:

    MATLAB与VB混合编程技术研究 WORD版
    MATLAB与VB混合编程技术研究 WORD版

    本文档主要讲述的是MATLAB与VB混合编程技术研究;着重探讨了在VB应用程序中集成MATLAB实现程序优化的四种方法,即利用Matrix VB、调用DLL动态链接库、应用Active自动化技术和动态数据交换技术,并分析了集成过程中的关键问题及其基本步骤。这种混合编程实现了VB的可视化界面与MATLAB强大的数值分析能力的结合。希望本文档会给有需要的朋友带来帮助;感兴趣的朋友可以过来看看

    下载
    • 当用户输入任务并点击“添加”按钮时,获取文本内容。
    • 更新一个计数器(例如,可以绑定在添加按钮的 data 属性上)。
    • 使用计数器作为键的一部分,将任务文本存储到 page.client_storage。
  3. 加载已存储任务:

    • 应用启动时,遍历 page.client_storage 中所有以特定前缀(例如“t”)开头的键。
    • 对于每个键,获取其对应的值(任务文本)。
    • 根据获取到的任务文本,动态创建 ft.Text 控件,并添加到任务列表中。
  4. 清除所有任务:

    • 当用户点击“清除所有任务”按钮时,调用 page.client_storage.clear() 清除所有数据。
    • 同时清空 UI 中的任务列表。

3.3 示例代码

import flet as ft

def main(page: ft.Page):
    # 页面基本设置
    page.window_center()
    page.window_width = 400
    page.window_height = 600
    page.title = "Flet 持久化待办事项"
    page.bgcolor = "#141414"

    # 1. 定义清除所有任务的函数
    def all_clear(e):
        # 清除 client_storage 中的所有数据
        page.client_storage.clear()
        # 清除 UI 中的所有任务控件
        task_column.controls.clear()
        # 更新页面
        page.update()

    # 设置浮动操作按钮用于清除所有任务
    page.floating_action_button = ft.FloatingActionButton(
        icon=ft.icons.CLEANING_SERVICES_ROUNDED,
        on_click=all_clear,
        bgcolor="#4B90BE",
        scale=0.95
    )

    # 2. 定义添加任务的函数
    def add_task(e):
        # 确保输入框不为空
        if tf.value:
            # 增加添加按钮的data属性作为任务的唯一ID计数器
            # add_button.data 初始值为 0,每次点击增加
            add_button.data += 1

            # 获取任务文本
            task_text = tf.value

            # 创建一个 ft.Text 控件来显示任务
            # 注意:这里我们创建了控件,但不会直接存储它
            task_control = ft.Text(task_text, color=ft.colors.WHITE)

            # 将任务控件添加到显示任务的列中
            task_column.controls.append(task_control)

            # 将任务文本存储到 client_storage
            # 使用 f"task_{add_button.data}" 作为唯一的键
            page.client_storage.set(f"task_{add_button.data}", task_text)

            # 清空输入框
            tf.value = ""

            # 更新页面以显示新任务和清空的输入框
            page.update()

            # 打印当前所有存储的键,用于调试
            print("当前存储的键:", page.client_storage.get_keys(''))

        # 如果输入框为空,则不执行任何操作
        else:
            tf.focus() # 重新聚焦输入框
            page.update()


    # 任务输入框
    tf = ft.TextField(
        label='输入新任务',
        expand=True, # 允许文本框扩展以填充可用空间
        color=ft.colors.WHITE,
        hint_text_style=ft.TextStyle(color=ft.colors.GREY_500)
    )

    # 添加任务按钮
    # data=0 用于作为任务ID的计数器
    add_button = ft.IconButton(
        icon=ft.icons.ADD,
        on_click=add_task,
        data=0,
        icon_color="#4B90BE",
        tooltip="添加任务"
    )

    # 用于显示所有任务的列
    task_column = ft.Column(
        controls=[],
        spacing=10 # 任务之间的间距
    )

    # 将输入框和添加按钮添加到页面顶部
    page.add(
        ft.Row(
            controls=[
                tf,
                add_button
            ],
            alignment=ft.MainAxisAlignment.CENTER
        )
    )

    # 将任务显示列添加到页面
    page.add(
        ft.Container(
            content=task_column,
            expand=True, # 允许任务列表扩展
            padding=ft.padding.all(10),
            alignment=ft.alignment.top_left
        )
    )

    # 3. 应用启动时加载已存储的任务
    # 检查 client_storage 中是否存在以 'task_' 开头的键
    stored_keys = page.client_storage.get_keys('task_')
    if stored_keys:
        # 对键进行排序,以确保任务按添加顺序显示
        # 提取数字部分进行排序,例如 'task_10' -> 10
        sorted_keys = sorted(stored_keys, key=lambda k: int(k.split('_')[1]))

        for key in sorted_keys:
            # 获取存储的任务文本
            task_text = page.client_storage.get(key)
            if task_text: # 确保获取到的值不为空
                # 根据任务文本创建 ft.Text 控件
                task_control = ft.Text(task_text, color=ft.colors.WHITE)
                # 将控件添加到任务显示列中
                task_column.controls.append(task_control)

                # 更新 add_button.data,确保新的任务ID不会与现有ID冲突
                # 找到最大的ID,并将其设置为 add_button.data 的起始值
                current_max_id = int(key.split('_')[1])
                if current_max_id > add_button.data:
                    add_button.data = current_max_id

        # 加载完成后,将 add_button.data 增加1,为下一个新任务做准备
        add_button.data += 1

        # 更新页面以显示加载的任务
        page.update()


# 运行 Flet 应用
ft.app(target=main)

3.4 注意事项与改进

  1. 唯一键管理: 在上述示例中,我们使用 add_button.data 作为计数器来生成唯一的任务键(例如 task_1, task_2)。这是一种简单有效的方法。在应用启动时,需要遍历所有已存储的键,找出最大的数字,并更新 add_button.data,以确保新添加的任务不会覆盖现有任务。

  2. 单个任务的删除: 示例中只实现了“清除所有任务”。如果需要删除单个任务,则在创建每个任务的 UI 控件时,需要将其对应的 client_storage 键关联起来(例如,通过 control.data 属性)。当删除按钮被点击时,可以根据这个键从 client_storage 中移除对应的数据,并从 UI 中移除该控件。

  3. 更复杂的数据结构: 如果需要存储更复杂的数据(例如,任务的文本、完成状态、截止日期等),可以考虑将每个任务存储为一个字典,然后将所有任务的字典列表进行 JSON 序列化,作为一个单一的值存储到 client_storage 中。

    import json
    # 存储
    tasks_data = [{"text": "Buy milk", "completed": False}, {"text": "Learn Flet", "completed": True}]
    page.client_storage.set("all_tasks", json.dumps(tasks_data))
    
    # 读取
    stored_json = page.client_storage.get("all_tasks")
    if stored_json:
        loaded_tasks = json.loads(stored_json)
        # 根据 loaded_tasks 重新构建 UI

    这种方式更易于管理和更新,因为它将所有相关数据存储在一个条目下。

4. 总结

page.client_storage 是 Flet 应用实现数据持久化的强大工具,但正确使用它至关重要。核心在于理解它是一个键值对存储,只能存储可序列化的数据,而非复杂的 Flet UI 控件对象。通过将数据与 UI 逻辑分离,并在应用启动时动态重建 UI,我们可以有效地利用 client_storage 来提升用户体验,确保应用数据的持久性。

相关专题

更多
python开发工具
python开发工具

php中文网为大家提供各种python开发工具,好的开发工具,可帮助开发者攻克编程学习中的基础障碍,理解每一行源代码在程序执行时在计算机中的过程。php中文网还为大家带来python相关课程以及相关文章等内容,供大家免费下载使用。

749

2023.06.15

python打包成可执行文件
python打包成可执行文件

本专题为大家带来python打包成可执行文件相关的文章,大家可以免费的下载体验。

635

2023.07.20

python能做什么
python能做什么

python能做的有:可用于开发基于控制台的应用程序、多媒体部分开发、用于开发基于Web的应用程序、使用python处理数据、系统编程等等。本专题为大家提供python相关的各种文章、以及下载和课程。

758

2023.07.25

format在python中的用法
format在python中的用法

Python中的format是一种字符串格式化方法,用于将变量或值插入到字符串中的占位符位置。通过format方法,我们可以动态地构建字符串,使其包含不同值。php中文网给大家带来了相关的教程以及文章,欢迎大家前来阅读学习。

618

2023.07.31

python教程
python教程

Python已成为一门网红语言,即使是在非编程开发者当中,也掀起了一股学习的热潮。本专题为大家带来python教程的相关文章,大家可以免费体验学习。

1262

2023.08.03

python环境变量的配置
python环境变量的配置

Python是一种流行的编程语言,被广泛用于软件开发、数据分析和科学计算等领域。在安装Python之后,我们需要配置环境变量,以便在任何位置都能够访问Python的可执行文件。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

547

2023.08.04

python eval
python eval

eval函数是Python中一个非常强大的函数,它可以将字符串作为Python代码进行执行,实现动态编程的效果。然而,由于其潜在的安全风险和性能问题,需要谨慎使用。php中文网给大家带来了相关的教程以及文章,欢迎大家前来学习阅读。

577

2023.08.04

scratch和python区别
scratch和python区别

scratch和python的区别:1、scratch是一种专为初学者设计的图形化编程语言,python是一种文本编程语言;2、scratch使用的是基于积木的编程语法,python采用更加传统的文本编程语法等等。本专题为大家提供scratch和python相关的文章、下载、课程内容,供大家免费下载体验。

706

2023.08.11

PHP 表单处理与文件上传安全实战
PHP 表单处理与文件上传安全实战

本专题聚焦 PHP 在表单处理与文件上传场景中的实战与安全问题,系统讲解表单数据获取与校验、XSS 与 CSRF 防护、文件类型与大小限制、上传目录安全配置、恶意文件识别以及常见安全漏洞的防范策略。通过贴近真实业务的案例,帮助学习者掌握 安全、规范地处理用户输入与文件上传的完整开发流程。

3

2026.01.13

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
最新Python教程 从入门到精通
最新Python教程 从入门到精通

共4课时 | 0.6万人学习

Django 教程
Django 教程

共28课时 | 3万人学习

SciPy 教程
SciPy 教程

共10课时 | 1.1万人学习

关于我们 免责申明 举报中心 意见反馈 讲师合作 广告合作 最新更新
php中文网:公益在线php培训,帮助PHP学习者快速成长!
关注服务号 技术交流群
PHP中文网订阅号
每天精选资源文章推送

Copyright 2014-2026 https://www.php.cn/ All Rights Reserved | php.cn | 湘ICP备2023035733号