1. 为什么选择Flet开发Todo应用第一次接触Flet框架时我正为团队寻找一个能快速开发轻量级应用的解决方案。传统桌面应用开发需要处理复杂的GUI框架而网页应用又涉及前后端分离的繁琐流程。Flet的出现完美解决了这些痛点——它让我们能用纯Python代码同时生成桌面端、移动端和Web端的应用界面。Todo应用作为生产力工具的代表是检验框架能力的绝佳试金石。一个完整的Todo应用需要处理用户输入、状态管理、数据持久化等核心功能正好覆盖了Flet的主要特性。我在实际项目中验证过用Flet从零开始构建一个功能完善的Todo应用熟练开发者只需2-3小时初学者也能在一天内完成。相比其他框架Flet有三个突出优势首先它内置了丰富的UI组件库从基础的文本框、按钮到复杂的选项卡、对话框一应俱全其次采用响应式编程模型状态变更会自动触发界面更新最重要的是它允许开发者用声明式语法构建界面就像搭积木一样简单。比如创建一个带输入框的Todo界面代码量不到20行import flet as ft def main(page): task_input ft.TextField(hint_text输入新任务) tasks ft.Column() def add_task(e): tasks.controls.append(ft.Checkbox(labeltask_input.value)) task_input.value page.update() page.add( ft.Row([task_input, ft.FloatingActionButton(iconft.icons.ADD, on_clickadd_task)]), tasks ) ft.app(targetmain)这段代码已经实现了一个可运行的Todo应用核心功能输入任务、添加任务、显示任务列表。Flet的控件命名非常直观即使没有文档也能猜出各组件的用途。TextField对应输入框FloatingActionButton是那个圆形加号按钮Column则是垂直排列的容器。当点击按钮时add_task函数会将输入框内容转为复选框项添加到列表中最后调用page.update()刷新界面。2. 搭建基础功能框架2.1 项目初始化与环境配置开始前需要确保Python版本≥3.8这是Flet的最低要求。我推荐使用虚拟环境隔离项目依赖避免与其他项目冲突。下面是创建和激活虚拟环境的命令python -m venv flet_env source flet_env/bin/activate # Linux/Mac flet_env\Scripts\activate # Windows安装Flet只需一行命令pip install flet建议同时安装flet-matplotlib等扩展库虽然Todo应用用不到但后续开发图表类功能时会很方便。我在项目中通常会创建一个requirements.txt文件记录所有依赖flet0.1.48 flet-matplotlib0.1.22.2 核心组件布局技巧一个标准的Todo界面通常包含四个区域标题栏、输入区、任务列表和底部状态栏。在Flet中这种布局可以用Column嵌套Row来实现。下面是我优化后的布局代码def main(page: ft.Page): page.title 高效Todo page.horizontal_alignment ft.CrossAxisAlignment.CENTER # 标题 header ft.Text(今日任务, styleheadlineMedium) # 输入区 new_task ft.TextField(hint_text输入任务内容..., expandTrue) add_button ft.FloatingActionButton(iconft.icons.ADD) # 任务列表 tasks ft.Column() # 底部状态栏 items_left ft.Text(0项待完成) clear_btn ft.OutlinedButton(text清除已完成) # 组合布局 page.add( ft.Column([ header, ft.Row([new_task, add_button]), tasks, ft.Row([items_left, clear_btn], alignmentft.MainAxisAlignment.SPACE_BETWEEN) ], width600) )这里有几个关键点值得注意expandTrue让输入框自动填充剩余空间CrossAxisAlignment.CENTER实现水平居中MainAxisAlignment.SPACE_BETWEEN让状态栏两侧元素分散对齐固定宽度600px确保在不同设备上显示一致2.3 事件处理与状态更新Flet采用事件驱动模型每个交互操作都会触发对应事件。为按钮添加点击事件的典型做法是def add_task(e): if new_task.value.strip(): tasks.controls.append( ft.Checkbox(labelnew_task.value, valueFalse)) new_task.value update_counter() add_button.on_click add_task这里的e参数包含事件相关信息虽然本例中没有使用。我添加了.strip()检查避免输入空任务这是实际开发中容易忽略的细节。update_counter函数用于实时更新未完成任务数def update_counter(): count sum(1 for task in tasks.controls if not task.value) items_left.value f{count}项待完成 page.update()注意每次界面变更后都要调用page.update()这是Flet与Flutter等框架的显著区别。虽然多写一行代码但让状态管理更加显式和可控。3. 高级功能实现3.1 任务管理功能扩展基础版Todo只能添加和完成任务实用场景还需要编辑和删除功能。我设计了一个Task类来封装单个任务的所有操作class Task(ft.UserControl): def __init__(self, name, delete_callback): super().__init__() self.name name self.delete_callback delete_callback self.completed False self.edit_input ft.TextField(expandTrue) def build(self): self.display_view ft.Row([ ft.Checkbox(valueFalse, on_changeself.status_changed), ft.Text(self.name), ft.Row([ ft.IconButton(iconft.icons.EDIT, on_clickself.edit), ft.IconButton(iconft.icons.DELETE, on_clickself.delete) ], spacing0) ], alignmentft.MainAxisAlignment.SPACE_BETWEEN) self.edit_view ft.Row([ self.edit_input, ft.IconButton(iconft.icons.DONE, on_clickself.save) ], visibleFalse) return ft.Column([self.display_view, self.edit_view]) def edit(self, e): self.edit_input.value self.name self.display_view.visible False self.edit_view.visible True self.update() def save(self, e): self.name self.edit_input.value self.display_view.visible True self.edit_view.visible False self.update() def delete(self, e): self.delete_callback(self) def status_changed(self, e): self.completed e.control.value self.update()这个设计模式有几个亮点使用UserControl创建可复用组件通过visible属性切换显示/编辑状态回调函数实现父组件通信内联样式保持代码整洁3.2 数据筛选与状态管理当任务数量增多时筛选功能变得尤为重要。Flet的Tabs组件非常适合实现这种需求filter_tabs ft.Tabs( selected_index0, tabs[ft.Tab(全部), ft.Tab(未完成), ft.Tab(已完成)], on_changefilter_changed ) def filter_changed(e): status filter_tabs.tabs[filter_tabs.selected_index].text for task in task_container.controls: task.visible ( status 全部 or (status 未完成 and not task.completed) or (status 已完成 and task.completed) ) page.update()配合前面实现的Task类现在可以按状态筛选任务了。我在实际使用中发现这种客户端过滤比服务端查询响应更快适合小型应用。3.3 数据持久化方案虽然Flet本身不提供数据持久化功能但可以轻松集成Python标准库的存储方案。对于Todo应用json是最简单的选择import json def save_tasks(): data [{name: task.name, completed: task.completed} for task in task_container.controls] with open(tasks.json, w) as f: json.dump(data, f) def load_tasks(): try: with open(tasks.json) as f: return json.load(f) except FileNotFoundError: return []在应用启动时加载数据for task_data in load_tasks(): task Task(task_data[name], delete_task) task.completed task_data[completed] task_container.controls.append(task)在每次变更后保存数据def add_task(e): # ...原有代码... save_tasks() def delete_task(task): task_container.controls.remove(task) save_tasks() update_counter()4. 界面优化与部署4.1 视觉体验提升技巧好的UI设计能显著提升使用体验。以下是几个简单但有效的优化方案添加动画效果Flet支持隐式动画比如给任务添加淡入效果task ft.Container( contentft.Checkbox(labeltask_name), opacity0, animate_opacity300 ) task.opacity 1主题定制统一应用风格page.theme ft.Theme( color_schemeft.ColorScheme( primaryft.colors.BLUE_ACCENT, secondaryft.colors.PINK_ACCENT ) )响应式布局适应不同屏幕尺寸page.on_resize lambda e: print(f窗口大小变为: {e.width}x{e.height})4.2 多平台打包发布Flet应用可以打包为独立可执行文件使用PyInstaller非常方便安装打包工具pip install pyinstaller创建打包脚本build.specblock_cipher None a Analysis([main.py], binaries[], datas[], hiddenimports[], hookspath[], runtime_hooks[], excludes[], win_no_prefer_redirectsFalse, win_private_assembliesFalse, cipherblock_cipher, nameMyTodoApp) pyz PYZ(a.pure, a.zipped_data, cipherblock_cipher) exe EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, nameMyTodoApp, debugFalse, bootloader_ignore_signalsFalse, stripFalse, upxTrue, runtime_tmpdirNone, consoleFalse)执行打包命令pyinstaller build.spec打包后的应用位于dist目录可以直接分发。对于Web部署Flet应用也能作为静态网站发布只需配置简单的Web服务器即可。
利用Flet框架打造高效Todo应用:从入门到实战
1. 为什么选择Flet开发Todo应用第一次接触Flet框架时我正为团队寻找一个能快速开发轻量级应用的解决方案。传统桌面应用开发需要处理复杂的GUI框架而网页应用又涉及前后端分离的繁琐流程。Flet的出现完美解决了这些痛点——它让我们能用纯Python代码同时生成桌面端、移动端和Web端的应用界面。Todo应用作为生产力工具的代表是检验框架能力的绝佳试金石。一个完整的Todo应用需要处理用户输入、状态管理、数据持久化等核心功能正好覆盖了Flet的主要特性。我在实际项目中验证过用Flet从零开始构建一个功能完善的Todo应用熟练开发者只需2-3小时初学者也能在一天内完成。相比其他框架Flet有三个突出优势首先它内置了丰富的UI组件库从基础的文本框、按钮到复杂的选项卡、对话框一应俱全其次采用响应式编程模型状态变更会自动触发界面更新最重要的是它允许开发者用声明式语法构建界面就像搭积木一样简单。比如创建一个带输入框的Todo界面代码量不到20行import flet as ft def main(page): task_input ft.TextField(hint_text输入新任务) tasks ft.Column() def add_task(e): tasks.controls.append(ft.Checkbox(labeltask_input.value)) task_input.value page.update() page.add( ft.Row([task_input, ft.FloatingActionButton(iconft.icons.ADD, on_clickadd_task)]), tasks ) ft.app(targetmain)这段代码已经实现了一个可运行的Todo应用核心功能输入任务、添加任务、显示任务列表。Flet的控件命名非常直观即使没有文档也能猜出各组件的用途。TextField对应输入框FloatingActionButton是那个圆形加号按钮Column则是垂直排列的容器。当点击按钮时add_task函数会将输入框内容转为复选框项添加到列表中最后调用page.update()刷新界面。2. 搭建基础功能框架2.1 项目初始化与环境配置开始前需要确保Python版本≥3.8这是Flet的最低要求。我推荐使用虚拟环境隔离项目依赖避免与其他项目冲突。下面是创建和激活虚拟环境的命令python -m venv flet_env source flet_env/bin/activate # Linux/Mac flet_env\Scripts\activate # Windows安装Flet只需一行命令pip install flet建议同时安装flet-matplotlib等扩展库虽然Todo应用用不到但后续开发图表类功能时会很方便。我在项目中通常会创建一个requirements.txt文件记录所有依赖flet0.1.48 flet-matplotlib0.1.22.2 核心组件布局技巧一个标准的Todo界面通常包含四个区域标题栏、输入区、任务列表和底部状态栏。在Flet中这种布局可以用Column嵌套Row来实现。下面是我优化后的布局代码def main(page: ft.Page): page.title 高效Todo page.horizontal_alignment ft.CrossAxisAlignment.CENTER # 标题 header ft.Text(今日任务, styleheadlineMedium) # 输入区 new_task ft.TextField(hint_text输入任务内容..., expandTrue) add_button ft.FloatingActionButton(iconft.icons.ADD) # 任务列表 tasks ft.Column() # 底部状态栏 items_left ft.Text(0项待完成) clear_btn ft.OutlinedButton(text清除已完成) # 组合布局 page.add( ft.Column([ header, ft.Row([new_task, add_button]), tasks, ft.Row([items_left, clear_btn], alignmentft.MainAxisAlignment.SPACE_BETWEEN) ], width600) )这里有几个关键点值得注意expandTrue让输入框自动填充剩余空间CrossAxisAlignment.CENTER实现水平居中MainAxisAlignment.SPACE_BETWEEN让状态栏两侧元素分散对齐固定宽度600px确保在不同设备上显示一致2.3 事件处理与状态更新Flet采用事件驱动模型每个交互操作都会触发对应事件。为按钮添加点击事件的典型做法是def add_task(e): if new_task.value.strip(): tasks.controls.append( ft.Checkbox(labelnew_task.value, valueFalse)) new_task.value update_counter() add_button.on_click add_task这里的e参数包含事件相关信息虽然本例中没有使用。我添加了.strip()检查避免输入空任务这是实际开发中容易忽略的细节。update_counter函数用于实时更新未完成任务数def update_counter(): count sum(1 for task in tasks.controls if not task.value) items_left.value f{count}项待完成 page.update()注意每次界面变更后都要调用page.update()这是Flet与Flutter等框架的显著区别。虽然多写一行代码但让状态管理更加显式和可控。3. 高级功能实现3.1 任务管理功能扩展基础版Todo只能添加和完成任务实用场景还需要编辑和删除功能。我设计了一个Task类来封装单个任务的所有操作class Task(ft.UserControl): def __init__(self, name, delete_callback): super().__init__() self.name name self.delete_callback delete_callback self.completed False self.edit_input ft.TextField(expandTrue) def build(self): self.display_view ft.Row([ ft.Checkbox(valueFalse, on_changeself.status_changed), ft.Text(self.name), ft.Row([ ft.IconButton(iconft.icons.EDIT, on_clickself.edit), ft.IconButton(iconft.icons.DELETE, on_clickself.delete) ], spacing0) ], alignmentft.MainAxisAlignment.SPACE_BETWEEN) self.edit_view ft.Row([ self.edit_input, ft.IconButton(iconft.icons.DONE, on_clickself.save) ], visibleFalse) return ft.Column([self.display_view, self.edit_view]) def edit(self, e): self.edit_input.value self.name self.display_view.visible False self.edit_view.visible True self.update() def save(self, e): self.name self.edit_input.value self.display_view.visible True self.edit_view.visible False self.update() def delete(self, e): self.delete_callback(self) def status_changed(self, e): self.completed e.control.value self.update()这个设计模式有几个亮点使用UserControl创建可复用组件通过visible属性切换显示/编辑状态回调函数实现父组件通信内联样式保持代码整洁3.2 数据筛选与状态管理当任务数量增多时筛选功能变得尤为重要。Flet的Tabs组件非常适合实现这种需求filter_tabs ft.Tabs( selected_index0, tabs[ft.Tab(全部), ft.Tab(未完成), ft.Tab(已完成)], on_changefilter_changed ) def filter_changed(e): status filter_tabs.tabs[filter_tabs.selected_index].text for task in task_container.controls: task.visible ( status 全部 or (status 未完成 and not task.completed) or (status 已完成 and task.completed) ) page.update()配合前面实现的Task类现在可以按状态筛选任务了。我在实际使用中发现这种客户端过滤比服务端查询响应更快适合小型应用。3.3 数据持久化方案虽然Flet本身不提供数据持久化功能但可以轻松集成Python标准库的存储方案。对于Todo应用json是最简单的选择import json def save_tasks(): data [{name: task.name, completed: task.completed} for task in task_container.controls] with open(tasks.json, w) as f: json.dump(data, f) def load_tasks(): try: with open(tasks.json) as f: return json.load(f) except FileNotFoundError: return []在应用启动时加载数据for task_data in load_tasks(): task Task(task_data[name], delete_task) task.completed task_data[completed] task_container.controls.append(task)在每次变更后保存数据def add_task(e): # ...原有代码... save_tasks() def delete_task(task): task_container.controls.remove(task) save_tasks() update_counter()4. 界面优化与部署4.1 视觉体验提升技巧好的UI设计能显著提升使用体验。以下是几个简单但有效的优化方案添加动画效果Flet支持隐式动画比如给任务添加淡入效果task ft.Container( contentft.Checkbox(labeltask_name), opacity0, animate_opacity300 ) task.opacity 1主题定制统一应用风格page.theme ft.Theme( color_schemeft.ColorScheme( primaryft.colors.BLUE_ACCENT, secondaryft.colors.PINK_ACCENT ) )响应式布局适应不同屏幕尺寸page.on_resize lambda e: print(f窗口大小变为: {e.width}x{e.height})4.2 多平台打包发布Flet应用可以打包为独立可执行文件使用PyInstaller非常方便安装打包工具pip install pyinstaller创建打包脚本build.specblock_cipher None a Analysis([main.py], binaries[], datas[], hiddenimports[], hookspath[], runtime_hooks[], excludes[], win_no_prefer_redirectsFalse, win_private_assembliesFalse, cipherblock_cipher, nameMyTodoApp) pyz PYZ(a.pure, a.zipped_data, cipherblock_cipher) exe EXE(pyz, a.scripts, a.binaries, a.zipfiles, a.datas, nameMyTodoApp, debugFalse, bootloader_ignore_signalsFalse, stripFalse, upxTrue, runtime_tmpdirNone, consoleFalse)执行打包命令pyinstaller build.spec打包后的应用位于dist目录可以直接分发。对于Web部署Flet应用也能作为静态网站发布只需配置简单的Web服务器即可。