Flet入门指南:用Python打造跨平台桌面GUI应用
1. 为什么选择Flet开发桌面GUI应用作为一个用Python写了十几年GUI的老码农第一次看到Flet时差点从椅子上跳起来——这玩意儿简直是把Flutter的强大和Python的简单粗暴完美结合了以前我们要做个跨平台桌面应用要么用PyQt这种笨重的框架要么得忍受Tkinter的复古界面现在终于有了更优雅的解决方案。Flet最让我惊艳的是它的**一次编写到处运行**特性。上周我刚用Flet给客户做了个数据可视化工具同一份代码直接在Windows、Mac和网页端都能完美运行连UI适配都不用操心。这可比当年用Electron打包省心多了毕竟Python的依赖管理比Node.js清爽不止一个量级。2. 5分钟快速上手Flet2.1 环境准备先确保你的Python版本在3.7以上推荐3.10然后就是经典的pip安装pip install flet装完可以跑个Hello World测试下import flet as ft def main(page): page.add(ft.Text(Hello, Flet!)) ft.app(targetmain)这个小例子已经包含了Flet的核心概念ft.Page是应用的画布ft.Text是基础控件ft.app()启动应用。我建议新手先把这个例子跑通再慢慢添加其他组件。2.2 第一个计数器应用原始文章里的计数器是个很好的教学案例我来扩展个带历史记录功能的版本import flet as ft def main(page): page.title 智能计数器 count ft.TextField(value0, width100) history ft.ListView(expandTrue) def record(op): history.controls.append( ft.Text(f操作{op} 结果{count.value}) ) page.update() def minus_click(e): count.value str(int(count.value) - 1) record(减1) def plus_click(e): count.value str(int(count.value) 1) record(加1) page.add( ft.Row([ ft.IconButton(ft.icons.REMOVE, on_clickminus_click), count, ft.IconButton(ft.icons.ADD, on_clickplus_click) ]), ft.Divider(), ft.Text(操作历史), history ) ft.app(targetmain, viewft.AppView.WEB_BROWSER)这个增强版展示了Flet的几个实用特性ListView实现滚动列表Divider添加分割线多组件垂直布局同时支持桌面和网页运行模式3. Flet核心组件实战3.1 布局系统详解Flet的布局逻辑和Flutter一脉相承主要靠Row、Column和Stack三大金刚。我常用的布局套路是ft.Column( controls[ ft.Row([控件1, 控件2]), # 水平排列 ft.Stack([ # 重叠布局 ft.Image(src背景图), ft.Text(前景文字) ]) ], spacing10, # 组件间距 expandTrue # 充满父容器 )避坑指南刚开始容易忘记设置expandTrue导致布局不填充窗口。另外建议用padding和margin控制间距比用空Text占位优雅多了。3.2 常用控件库Flet几乎移植了Flutter的所有基础控件这里推荐几个高频使用的控件类型常用组件典型用途输入类TextField, Dropdown, Slider表单数据收集展示类Text, Image, ProgressBar信息呈现操作类ElevatedButton, IconButton用户交互布局类ListView, GridView, Card界面组织来个综合案例——简易待办事项应用def main(page): tasks ft.Column() new_task ft.TextField(hint_text输入新任务) def add_task(e): tasks.controls.append( ft.Checkbox(labelnew_task.value) ) new_task.value page.update() page.add( ft.Text(待办清单, size20), ft.Row([ new_task, ft.ElevatedButton(添加, on_clickadd_task) ]), tasks )4. 进阶开发技巧4.1 状态管理方案当应用变复杂后推荐使用page.client_storage实现本地持久化。比如给待办应用加个自动保存功能def main(page): # 读取本地存储 saved_tasks page.client_storage.get(tasks) or [] tasks ft.Column( controls[ft.Checkbox(labelt) for t in saved_tasks] ) def save_tasks(): page.client_storage.set( tasks, [t.label for t in tasks.controls] )4.2 打包发布实战用PyInstaller打包Flet应用时要注意几个关键参数pyinstaller --onefile --add-data assets;assets app.py踩坑记录遇到过打包后图标不显示的问题后来发现要把资源文件放在同级目录的assets文件夹里。另外建议在代码里加个资源路径判断import sys import os if getattr(sys, frozen, False): base_path sys._MEIPASS else: base_path os.path.abspath(.)5. 企业级应用开发建议最近用Flet做了个库存管理系统总结了几条实战经验模块化开发把UI组件拆分成独立类/文件主题统一提前定义好颜色和字体样式错误处理用try-except包裹关键操作性能优化大数据集用ListView.builder懒加载典型的企业应用架构class MainApp: def __init__(self, page): self.page page self._init_ui() def _init_ui(self): self.sidebar self._build_sidebar() self.content ft.Column() self.page.add( ft.Row([self.sidebar, self.content]) ) def _build_sidebar(self): return ft.Column([ ft.ElevatedButton(仪表盘, on_clickself.show_dashboard), ft.ElevatedButton(报表, on_clickself.show_report) ])这种架构下每个功能模块对应一个方法通过修改self.content来切换视图比一堆全局变量清爽多了。