传奇开心果创意编程微博文系列
- 前言
- 一、使用tabs组件搭建桌面程序雏形框架,正宗、规范开局
- 二、自主创新自定义选项卡组件CustomTab实现自己多年夙愿和时尚追求的界面设计
- 三、修改标签被选中时会改变样式以指示其活动状态,打造升级版自定义选项卡组件customtab Pro
- 四、customtab Pro自定义选项卡升级版组件标签选中和未选中两种背景颜色变化重新配色,并且给选项卡标签启用墨水效果打造自定义选项卡升级版再升级版customtab Pro_up
- 五、对应编程任务修改相关文字和图标
- 六、使用Flet框架和自定义选项卡customtab Pro组件自定义标题栏实现仿360安全卫士界面自定义模板示例
- 七、购物清单助手桌面程序框架搭建完毕,二次开发有了基础
- 八、全文总结
前言
实现360桌面程序那样酷炫的界面,变异奇特的造型,是我很早以前的梦想,也可以说是夙愿了。试了很多UI框架,都不尽人意,或者是自定义能力有限,或者是自定义难度较大,灵活性不足。对我来说,可以说夙愿难了,最近发现了Flet框架,听介绍说控件自定义和控件组合能力特别强,还简单高效,漂亮时尚。我大胆试水,果然是这样,几天时间就如愿以偿,圆了少年梦想。以前,说起Python语言,做做后端开发还可以,Pythongui做成的UI界面基本就是土气,丑陋不堪。Flet框架的出现石破天惊,改变了这个局面,因为它继承了flutter时尚漂亮的基因,无处不在的丝滑灵动的动画,细微和谐赏心悦目的色差调色,漂亮美观的现代元素的组件比比皆是,信手拈来,都是专业级别的。语法继承了Python语言的贴近自然语言特性,不限于此,还做了大量组件封装,写代码和语法理解简单明了,高效快捷,容易上手,对初学者很友好。自适应和响应式布局,跨平台跨端都显示出了很好的适应性。一登场,一个华丽的亮相,就让人瞠目结舌,惊掉了眼镜。作为一个诞生才两年的UI框架,目前,还不尽人意的是打包安卓iOS手机应用必须拥有高速稳定的网络,普通网络成功率低。更大的痛点是继承了flutter依赖配置繁琐复杂,报错频繁,让人不胜其烦。写代码记事本都能写,显然不怎么依赖IDE,很贴心又舒心。但说起打包部署来,我不得不吐槽。就一个环境配置,Android studio要安装,VSstudio要安装,JDK要安装,AndroidSDK要安装,flutter要安装,grade要安装,都是重装备。小马拉大车那叫个费劲,满眼都是任性和尴尬!Flet开发是轻盈快捷,打包部署就是大雨天泥泞路上人抗马拉重装备,行军路上那叫个艰难!爱恨情仇,就都是她了!情未了,一波未平,一波又起,Flet框架为Python语言前端开发涂写了浓墨重彩的一笔。不容置疑,她的诞生,使Python成为了前端开发一道靓丽的风景线。
一、使用tabs组件搭建桌面程序雏形框架,正宗、规范开局
1.编程思路
创建新页面,添加tabs组件,使用tabs组件实现单击标签切换内容页面。
2.示例代码:
import flet as ft
def main(page: ft.Page):
t = ft.Tabs(
selected_index=1,
animation_duration=300,
tabs=[
ft.Tab(
text="Tab 1",
content=ft.Container(
content=ft.Text("这是 Tab 1"), alignment=ft.alignment.center
),
),
ft.Tab(
tab_content=ft.Icon(ft.icons.SEARCH),
content=ft.Text("这是 Tab 2"),
),
ft.Tab(
text="Tab 3",
icon=ft.icons.SETTINGS,
content=ft.Text("这是 Tab 3"),
),
],
expand=1,
)
page.add(t)
ft.app(target=main)
3.解释说明:
拿来主义,直接使用官方教程tabs组件源代码,创建购物清单助手桌面版程序窗口界面雏形框架。就从使用经典范例代码开始,正宗、规范开局。
4. 运行效果,截图为证
二、自主创新自定义选项卡组件CustomTab实现自己多年夙愿和时尚追求的界面设计
1.编程思路:
官方tabs组件不符合项目要求,为了拥有自己设想的选项卡特性,在Flet微信交流群网友的启迪和鼓励下,积极探索探究,苦心钻研,使用Flet组合控件的方式自主创新自定义选项卡控件CustomTab,开源发布,实现心中夙愿。这是本程序开发一大亮点,也为Flet生态和开源作出自己的贡献。以萤火虫微弱的光亮,在茫茫黑夜,为探索者脚下和眼前点亮一盏小桔灯。
2.示例代码:
示例代码如下:
import flet as ft
class CustomTab:
def __init__(self, text, icon_path, on_click=None):
self.text = text
self.icon_path = icon_path
self.on_click = on_click
def build(self):
# 创建显示图标的行
image_row = ft.Row(
[ft.Image(src=self.icon_path, width=64, height=64)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建显示文本的行
text_row = ft.Row(
[ft.Text(self.text, color=ft.colors.WHITE, size=16)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建包含图标和文本的列
container = ft.Column(
[image_row, text_row],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=5
)
return ft.Container(
content=container,
bgcolor=ft.colors.GREEN_500,
height=128,
width=128,
border_radius=8,
on_click=self.on_click
)
def main(page: ft.Page):
current_tab = None
content_container = ft.Column() # 用于显示页面内容的容器
# 定义每个标签对应的内容
tab_contents = {
"我的通讯": ft.Text("这是我的通讯页面", bgcolor=ft.colors.RED),
"网络收藏": ft.Text("这是网络收藏页面", bgcolor=ft.colors.ORANGE),
"电脑清理": ft.Text("这是电脑清理页面", bgcolor=ft.colors.GREEN),
"系统修复": ft.Text("这是系统修复页面", bgcolor=ft.colors.BLUE),
"我的笔记": ft.Text("这是我的笔记页面", bgcolor=ft.colors.PURPLE),
"功能大全": ft.Text("这是功能大全页面", bgcolor=ft.colors.YELLOW),
}
def tab_clicked(e):
nonlocal current_tab
tab_text = e.control.content.controls[1].controls[0].value # 获取被点击的标签文本
print(f"{
tab_text} tab clicked")
# 更新当前标签的背景颜色
if current_tab:
current_tab.bgcolor = ft.colors.GREEN_500
current_tab = e.control
current_tab.bgcolor = ft.colors.GREEN_700
page.update()
# 更新内容容器中的内容
content_container.clean() # 清空旧内容
content_container.controls.append(tab_contents.get(tab_text, ft.Text("未知页面")))
page.update()
# 创建并添加所有标签
tabs = ft.Row(
[
CustomTab(text="我的通讯", icon_path="aa.png", on_click=tab_clicked).build(),
CustomTab(text="网络收藏", icon_path="bb.png", on_click=tab_clicked).build(),
CustomTab(text="电脑清理", icon_path="cc.png", on_click=tab_clicked).build(),
CustomTab(text="系统修复", icon_path="dd.png", on_click=tab_clicked).build(),
CustomTab(text="我的笔记", icon_path="ee.png", on_click=tab_clicked).build(),
CustomTab(text="功能大全", icon_path="ff.png", on_click=tab_clicked).build(),
],
alignment=ft.MainAxisAlignment.START
)
page.add(tabs, content_container) # 添加标签和内容容器到页面
ft.app(target=main)
3. 解释说明:
“雄关漫道真如铁,而今迈步从头越。从头越,苍山如海,残阳多血。”引用毛主席的诗歌抒怀,开始下面的示例代码解释说明。
上述Python代码使用了Flet库来创建一个具有自定义标签栏的应用程序。以下是该代码的主要功能和组成部分的概述:
CustomTab类:这是一个自定义类,用于创建带有图标和文本的标签。每个标签都有独特的自定义样式,自定义图标和文本,每个标签可以指定文本、图标路径以及可选的点击事件处理函数。并且在自定义标签被选中时会改变样式以指示其活动状态。
main函数:这是应用程序的主入口点,定义了页面布局和交互逻辑。
初始化变量current_tab用于跟踪当前选中的标签。
content_container是一个Column控件,用于动态展示不同标签对应的内容。
定义了一个字典tab_contents,其中键是标签的文本,值是与这些标签关联的内容组件。
tab_clicked函数处理标签被点击时的行为,包括更新当前标签的状态(背景颜色)和更新内容容器以显示新的内容。
创建了一个包含多个CustomTab实例的水平布局Row,这些实例分别代表不同的标签,并且为每个标签指定了点击事件处理器。
最后将标签栏和内容容器添加到页面上,并通过ft.app(target=main)启动应用程序。
整体来看,这段代码实现了一个新颖漂亮的标签切换界面,用户可以通过点击美观漂亮的标签来浏览不同的内容区域。每个标签都有独特的自定义样式,自定义图标和文本,并且在被选中时会改变样式以指示其活动状态。
“黄洋界上炮声隆,报道敌军宵遁。”以毛主席的另外两句诗抒怀结束这一段解说。
4. 运行效果,截图为证
三、修改标签被选中时会改变样式以指示其活动状态,打造升级版自定义选项卡组件customtab Pro
1.编程思路:
未选中图标背景为light green,选中背景变为light yellow,通过标签被选中时会改变样式以指示其活动状态。初始为:未选中。
2.示例代码:
示例代码如下:
import flet as ft
class CustomTab:
def __init__(self, text, icon_path, on_click=None):
self.text = text
self.icon_path = icon_path
self.on_click = on_click
self.bgcolor = ft.colors.LIGHT_GREEN # 设置初始背景色为亮绿色
def build(self):
# 创建显示图标的行
image_row = ft.Row(
[ft.Image(src=self.icon_path, width=64, height=64)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建显示文本的行
text_row = ft.Row(
[ft.Text(self.text, color=ft.colors.WHITE, size=16)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建包含图标和文本的列
container = ft.Column(
[image_row, text_row],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=5
)
return ft.Container(
content=container,
bgcolor=self.bgcolor, # 使用类变量来设置背景色
height=128,
width=128,
border_radius=8,
on_click=self.on_click
)
def main(page: ft.Page):
current_tab = None
content_container = ft.Column() # 用于显示页面内容的容器
# 定义每个标签对应的内容
tab_contents = {
"我的通讯": ft.Text("这是我的通讯页面", bgcolor=ft.colors.RED),
"网络收藏": ft.Text("这是网络收藏页面", bgcolor=ft.colors.ORANGE),
"电脑清理": ft.Text("这是电脑清理页面", bgcolor=ft.colors.GREEN),
"系统修复": ft.Text("这是系统修复页面", bgcolor=ft.colors.BLUE),
"我的笔记": ft.Text("这是我的笔记页面", bgcolor=ft.colors.PURPLE),
"功能大全": ft.Text("这是功能大全页面", bgcolor=ft.colors.YELLOW),
}
def tab_clicked(e):
nonlocal current_tab
tab_text = e.control.content.controls[1].controls[0].value # 获取被点击的标签文本
print(f"{tab_text} tab clicked")
# 更新当前标签的背景颜色
if current_tab:
current_tab.bgcolor = ft.colors.LIGHT_GREEN # 将之前的标签背景色改为亮绿色
page.update(current_tab)
current_tab = e.control
current_tab.bgcolor = ft.colors.YELLOW # 将当前点击的标签背景色改为黄色
page.update(current_tab)
# 更新内容容器中的内容
content_container.clean() # 清空旧内容
content_container.controls.append(tab_contents.get(tab_text, ft.Text("未知页面")))
page.update(content_container)
# 创建并添加所有标签
tabs = ft.Row(
[
CustomTab(text="我的通讯", icon_path="aa.png", on_click=tab_clicked).build(),
CustomTab(text="网络收藏", icon_path="bb.png", on_click=tab_clicked).build(),
CustomTab(text="电脑清理", icon_path="cc.png", on_click=tab_clicked).build(),
CustomTab(text="系统修复", icon_path="dd.png", on_click=tab_clicked).build(),
CustomTab(text="我的笔记", icon_path="ee.png", on_click=tab_clicked).build(),
CustomTab(text="功能大全", icon_path="ff.png", on_click=tab_clicked).build(),
],
alignment=ft.MainAxisAlignment.START
)
page.add(tabs, content_container) # 添加标签和内容容器到页面
ft.app(target=main)
3. 解释说明
让我们详细说明一下代码中的颜色变化逻辑及其具体实现方式。
颜色变化逻辑概述
在这个代码中,实现了标签点击时背景颜色的变化逻辑。具体来说,有以下几个关键点:
初始状态:
所有标签的初始背景色均为亮绿色 (ft.colors.LIGHT_GREEN)。
点击事件处理:
当用户点击某个标签时,会触发 tab_clicked 函数。
在 tab_clicked 函数中,首先获取当前被点击的标签文本。
如果之前有选中的标签(即 current_tab 不为 None),则将它的背景色恢复为亮绿色。
将当前点击的标签背景色改为黄色 (ft.colors.YELLOW)。
更新页面以反映背景颜色的变化。
页面更新:
只对必要的控件进行更新,以减少页面重绘的次数。
具体来说,先更新之前的标签背景色,再更新当前点击的标签背景色,最后更新内容容器中的内容。
详细步骤说明
初始化标签:
每个标签的初始背景色设置为亮绿色 (ft.colors.LIGHT_GREEN)。
标签的 on_click 属性绑定到 tab_clicked 函数。
点击事件处理:
tab_clicked 函数接收点击事件 e。
获取当前点击的标签文本。
如果之前有选中的标签(即 current_tab 不为 None),将其背景色恢复为亮绿色,并更新页面。
将当前点击的标签背景色改为黄色,并更新页面。
清空内容容器,并添加新的页面内容。
打造升级版自定义选项卡组件任务完成,自定义选项卡组件更加优秀。
Flet组件tabs自主创新自定义组件升级版CustomTab Pro源代码
修改标签被选中时会改变样式以指示其活动状态,打造升级版自定义选项卡组件。
未选中图标背景为light green,选中背景变为yellow,通过标签被选中时会改变样式以指示其活动状态。初始为:未选中。
CustomTab类:这是一个自定义类,用于创建每个标签都有独特的自定义样式,自定义图标和文本的标签。每个标签可以指定文本、图标路径以及可选的点击事件处理函数。
main函数:这是应用程序的主入口点,定义了页面布局和交互逻辑。
初始化变量current_tab用于跟踪当前选中的标签。
content_container是一个Column控件,用于动态展示不同标签对应的内容。
定义了一个字典tab_contents,其中键是标签的文本,值是与这些标签关联的内容组件。
tab_clicked函数处理标签被点击时的行为,包括更新当前标签的状态(背景颜色)和更新内容容器以显示新的内容。
创建了一个包含多个CustomTab实例的水平布局Row,这些实例分别代表不同的标签,并且为每个标签指定了点击事件处理器。
最后将标签栏和内容容器添加到页面上,并通过ft.app(target=main)启动应用程序。
整体来看,这段代码实现了一个新颖漂亮的标签切换界面,用户可以通过点击美观漂亮的标签来浏览不同的内容区域。每个标签都有独特的自定义样式,自定义图标和文本,并且在被选中时会改变样式以指示其活动状态。
4.运行效果,截图为证
四、customtab Pro自定义选项卡升级版组件标签选中和未选中两种背景颜色变化重新配色,并且给选项卡标签启用墨水效果打造自定义选项卡升级版再升级版customtab Pro_up
1.编程思路
bgcolor=ft.colors.GREEN_200, # 背景颜色设置为浅绿色,bgcolor=ft.colors.AMBER, # 背景颜色设置为琥珀色。
设置ink=True, # 启用墨水效果。给自定义选项卡标签开启墨水效果。这将使得当用户点击或触摸选项卡标签时,会出现一个视觉反馈,即所谓的“墨水溅洒”效果。
2.示例代码
import flet as ft
class CustomTab:
def __init__(self, text, icon_path, on_click=None):
self.text = text
self.icon_path = icon_path
self.on_click = on_click
self.bgcolor = ft.colors.GREEN_200 # 设置初始背景色为浅绿色
def build(self):
# 创建显示图标的行
image_row = ft.Row(
[ft.Image(src=self.icon_path, width=64, height=64)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建显示文本的行
text_row = ft.Row(
[ft.Text(self.text, color=ft.colors.WHITE, size=16)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建包含图标和文本的列
container = ft.Column(
[image_row, text_row],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=5
)
# 添加 ink 效果
return ft.Container(
content=container,
bgcolor=self.bgcolor, # 使用类变量来设置背景色
height=128,
width=128,
border_radius=8,
on_click=self.on_click,
ink=True # 添加墨水效果
)
def main(page: ft.Page):
current_tab = None
content_container = ft.Column() # 用于显示页面内容的容器
# 定义每个标签对应的内容
tab_contents = {
"我的通讯": ft.Text("这是我的通讯页面", bgcolor=ft.colors.RED),
"网络收藏": ft.Text("这是网络收藏页面", bgcolor=ft.colors.ORANGE),
"电脑清理": ft.Text("这是电脑清理页面", bgcolor=ft.colors.GREEN),
"系统修复": ft.Text("这是系统修复页面", bgcolor=ft.colors.BLUE),
"我的笔记": ft.Text("这是我的笔记页面", bgcolor=ft.colors.PURPLE),
"功能大全": ft.Text("这是功能大全页面", bgcolor=ft.colors.YELLOW),
}
def tab_clicked(e):
nonlocal current_tab
tab_text = e.control.content.controls[1].controls[0].value # 获取被点击的标签文本
print(f"{
tab_text} tab clicked")
# 更新当前标签的背景颜色
if current_tab:
current_tab.bgcolor = ft.colors.GREEN_200 # 将之前的标签背景色改为浅绿色
page.update(current_tab)
current_tab = e.control
current_tab.bgcolor = ft.colors.AMBER # 将当前点击的标签背景色改为琥珀色
page.update(current_tab)
# 更新内容容器中的内容
content_container.clean() # 清空旧内容
content_container.controls.append(tab_contents.get(tab_text, ft.Text("未知页面")))
page.update(content_container)
# 创建并添加所有标签
tabs = ft.Row(
[
CustomTab(text="我的通讯", icon_path="aa.png", on_click=tab_clicked).build(),
CustomTab(text="网络收藏", icon_path="bb.png", on_click=tab_clicked).build(),
CustomTab(text="电脑清理", icon_path="cc.png", on_click=tab_clicked).build(),
CustomTab(text="系统修复", icon_path="dd.png", on_click=tab_clicked).build(),
CustomTab(text="我的笔记", icon_path="ee.png", on_click=tab_clicked).build(),
CustomTab(text="功能大全", icon_path="ff.png", on_click=tab_clicked).build(),
],
alignment=ft.MainAxisAlignment.START
)
page.add(tabs, content_container) # 添加标签和内容容器到页面
ft.app(target=main)
3. 解释说明
为了给选项卡的标签添加墨水效果(Ink Effect),我们需要修改 CustomTab 类中的 build 方法,具体是在 ft.Container 控件中添加 ink=True 参数。这将使得当用户点击或触摸选项卡时,会出现一个视觉反馈,即所谓的“墨水溅洒”效果。通过在 ft.Container 中添加 ink=True 参数,我们实现了选项卡的墨水效果。当用户点击某个选项卡时,将会看到一个短暂的视觉反馈。
**4. 运行效果,截图为证 **
五、对应编程任务修改相关文字和图标
1.编程思路
修改相关文字和图标适应购物清单助手桌面程序需求。
2.示例代码
import flet as ft
class CustomTab:
def __init__(self, text, icon_path, on_click=None):
self.text = text
self.icon_path = icon_path
self.on_click = on_click
self.bgcolor = ft.colors.GREEN_200 # 设置初始背景色为浅绿色
def build(self):
# 创建显示图标的行
image_row = ft.Row(
[ft.Image(src=self.icon_path, width=64, height=64)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建显示文本的行
text_row = ft.Row(
[ft.Text(self.text, color=ft.colors.WHITE, size=16)],
alignment=ft.MainAxisAlignment.CENTER
)
# 创建包含图标和文本的列
container = ft.Column(
[image_row, text_row],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=5
)
# 添加 ink 效果
return ft.Container(
content=container,
bgcolor=self.bgcolor, # 使用类变量来设置背景色
height=128,
width=128,
border_radius=8,
on_click=self.on_click,
ink=True # 添加墨水效果
)
def main(page: ft.Page):
current_tab = None
content_container = ft.Column() # 用于显示页面内容的容器
# 定义每个标签对应的内容
tab_contents = {
"我的选购": ft.Text("这是我的选购页面", bgcolor=ft.colors.RED),
"清单详情": ft.Text("这是清单详情页面", bgcolor=ft.colors.ORANGE),
"添加商品": ft.Text("这是添加商品页面", bgcolor=ft.colors.GREEN),
"保存商品": ft.Text("这是保存商品页面", bgcolor=ft.colors.BLUE),
"删除商品": ft.Text("这是删除商品页面", bgcolor=ft.colors.PURPLE),
"联系我们": ft.Text("这是联系我们页面", bgcolor=ft.colors.YELLOW),
}
def tab_clicked(e):
nonlocal current_tab
tab_text = e.control.content.controls[1].controls[0].value # 获取被点击的标签文本
print(f"{
tab_text} tab clicked")
# 更新当前标签的背景颜色
if current_tab:
current_tab.bgcolor = ft.colors.GREEN_200 # 将之前的标签背景色改为浅绿色
page.update(current_tab)
current_tab = e.control
current_tab.bgcolor = ft.colors.AMBER # 将当前点击的标签背景色改为琥珀色
page.update(current_tab)
# 更新内容容器中的内容
content_container.clean() # 清空旧内容
content_container.controls.append(tab_contents.get(tab_text, ft.Text("未知页面")))
page.update(content_container)
# 创建并添加所有标签
tabs = ft.Row(
[
CustomTab(text="我的选购", icon_path="gg.png", on_click=tab_clicked).build(),
CustomTab(text="清单详情", icon_path="hh.png", on_click=tab_clicked).build(),
CustomTab(text="添加商品", icon_path="ii.png", on_click=tab_clicked).build(),
CustomTab(text="保存商品", icon_path="jj.png", on_click=tab_clicked).build(),
CustomTab(text="删除商品", icon_path="kk.png", on_click=tab_clicked).build(),
CustomTab(text="联系我们", icon_path="ll.png", on_click=tab_clicked).build(),
],
alignment=ft.MainAxisAlignment.START
)
page.add(tabs, content_container) # 添加标签和内容容器到页面
ft.app(target=main)
3. 解释说明
我们按照要求修改标签的文本和图标路径。
我的通讯 修改为 我的选购,图标为 gg.png
网络收藏 修改为 清单详情,图标为 hh.png
电脑清理 修改为 添加商品,图标为 ii.png
系统修复 修改为 保存商品,图标为 jj.png
我的笔记 修改为 删除商品,图标为 kk.png
功能大全 修改为 联系我们,图标为 ll.png
**4. 运行效果,截图为证 **
六、使用Flet框架和自定义选项卡customtab Pro组件自定义标题栏实现仿360安全卫士界面自定义模板示例
1.编程思路
自定义选项卡customtab Pro组件自定义标题栏实现仿360安全卫士界面自定义模板
2.示例代码
import flet as ft
class CustomTab:
def __init__(self, text, icon_path, on_click=None):
self.text = text
self.icon_path = icon_path
self.on_click = on_click
self.container = None
def build(self):
self.container = ft.Container(
content=ft.Column(
controls=[
ft.Row(
controls=[ft.Image(src=self.icon_path, width=64, height=64)],
alignment=ft.MainAxisAlignment.CENTER
),
ft.Row(
controls=[ft.Text(self.text, color=ft.colors.WHITE, size=16)],
alignment=ft.MainAxisAlignment.CENTER
)
],
alignment=ft.MainAxisAlignment.CENTER,
spacing=5
),
bgcolor=ft.colors.GREEN_500,
height=200,
width=200,
on_click=self.on_click,
ink=True # 确保具有墨水效果
)
return self.container
def create_tab(text, icon_path, on_click):
return CustomTab(text=text, icon_path=icon_path, on_click=on_click).build()
def main(page: ft.Page):
# 设置窗口的初始大小和样式
page.window.width = 1220
page.window.height = 800
page.window.frameless = True
page.window.resizable = False
current_tab = None
content_container = ft.Column()
tab_contents = {
"我的选购": ft.Text("这是我的选购页面", bgcolor=ft.colors.RED),
"清单详情": ft.Text("这是清单详情页面", bgcolor=ft.colors.ORANGE),
"添加商品": ft.Text("这是添加商品页面", bgcolor=ft.colors.GREEN),
"保存商品": ft.Text("这是保存商品页面", bgcolor=ft.colors.BLUE),
"删除商品": ft.Text("这是删除商品页面", bgcolor=ft.colors.PURPLE),
"联系我们": ft.Text("这是联系我们页面", bgcolor=ft.colors.YELLOW),
}
def tab_clicked(e):
nonlocal current_tab
tab_text = e.control.content.controls[1].controls[0].value
print(f"{
tab_text} tab clicked")
if current_tab:
current_tab.bgcolor = ft.colors.GREEN_500
current_tab = e.control
current_tab.bgcolor = ft.colors.GREEN_200
page.update()
content_container.clean()
content_container.controls.append(tab_contents[tab_text])
page.update()
# 创建顶部标题栏
def create_app_title():
app_title_row = ft.Row(
controls=[
ft.IconButton(ft.icons.SHOPPING_CART, tooltip="购物车", icon_color=ft.colors.WHITE),
ft.Text("购物清单助手桌面程序1.0", color=ft.colors.WHITE, size=16)
],
alignment=ft.MainAxisAlignment.START
)
close_button = ft.IconButton(
ft.icons.CLOSE,
tooltip="关闭",
icon_color=ft.colors.RED,
on_click=lambda e: page.window.close()
)
icons_row = ft.Row(
controls=[
ft.IconButton(ft.icons.HOME, tooltip="首页", icon_color=ft.colors.WHITE),
ft.IconButton(ft.icons.SEARCH, tooltip="搜索", icon_color=ft.colors.WHITE),
ft.IconButton(ft.icons.SETTINGS, tooltip="设置", icon_color=ft.colors.WHITE),
close_button
],
alignment=ft.MainAxisAlignment.END
)
top_row_container = ft.Container(
content=ft.Row(
controls=[app_title_row, icons_row],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
height=50,
width=1220
),
bgcolor=ft.colors.GREEN_500,
padding=10,
)
return top_row_container
# 创建标签栏
def create_tabs():
tabs = ft.Row(
[
create_tab(text="我的选购", icon_path="gg.png", on_click=tab_clicked),
create_tab(text="清单详情", icon_path="hh.png", on_click=tab_clicked),
create_tab(text="添加商品", icon_path="ii.png", on_click=tab_clicked),
create_tab(text="保存商品", icon_path="jj.png", on_click=tab_clicked),
create_tab(text="删除商品", icon_path="kk.png", on_click=tab_clicked),
create_tab(text="联系我们", icon_path="ll.png", on_click=tab_clicked),
],
alignment=ft.MainAxisAlignment.START,
spacing=0,
width=1200
)
return tabs
# 创建布局
layout_column = ft.Column(
controls=[create_app_title(), create_tabs()],
spacing=0
)
page.add(layout_column, content_container)
ft.app(target=main)
3. 解释说明
这段代码的特色包括:
自定义组件:通过定义 CustomTab 类,创建了可重复使用的选项卡组件,方便管理与展示不同的功能,使得代码结构更加清晰和模块化。
用户界面设计:应用程序的界面设计考虑了布局的美观性和实用性,使用了图标和文本,增强了用户体验。顶部区域有明显的标题和功能图标,易于识别。
互动性:选项卡的点击事件处理增强了应用的互动性,用户点击不同的选项卡后,可以动态更换页面内容,使得操作更加流畅和直观。还添加了点击选项卡产生墨水效果功能,自定义选项卡视觉效果更加酷炫了。
颜色风格:使用丰富的颜色来区分不同的选项和内容,如 GREEN_500 和 GREEN_200,不仅美观,还能有效引导用户注意力。
灵活性与可扩展性:通过使用字典 tab_contents 来存储各选项卡的内容,使得后期扩展更为简单,能够轻松添加新的功能或页面。
窗体属性设置:通过设置窗口的大小、边框以及可调整性,增强了应用的适应性,提供了更加专注的用户体验(如无边框设计)。
响应式布局:整体布局使用了 Flet 提供的响应式控件(如 Row 和 Column),使得元素能够在不同分辨率的窗口中合理排列。
这些特色结合在一起,形成了一个结构清晰、易于使用且具备漂亮美观用户界面的桌面应用程序UI界面。
**4. 运行效果,截图为证 **
七、购物清单助手桌面程序框架搭建完毕,二次开发有了基础
1.编程思路
在我的选购内容页面添加输入框和添加、保存、删除三个按钮,添加列表视图。在清单详情内容页面添加数据表。合理布局,美化界面。实现购物清单助手的功能逻辑。在我的联系内容页面实现作者logo圆形头像加载。实现作者创作信息文字加载。使用sqlite3数据库实现数据永久加载。还有几个内容页面有待进一步扩展功能,二次开发。
完成搭建购物清单助手桌面程序框架的工作,二次开发有了脚手架和基本框架。开源发布,允许修改源代码二次开发,允许商业开发。
2.示例代码
import flet as ft
import sqlite3
import os
# 常量定义
DB_NAME = 'shopping_list.db'
PRIMARY_COLOR = ft.colors.GREEN_500
SECONDARY_COLOR = ft.colors.GREEN_400
BG_COLOR = ft.colors.WHITE
WINDOW_WIDTH = 1248
WINDOW_HEIGHT = 840
class ShoppingListApp:
def __init__(self):
self.page = None
self.items = []
self.current_tab = None
self.name_field = None
self.list_view = None
self.data_table = None
self.tab_contents = None
def init_db(self):
if not os.path.exists(DB_NAME):
with sqlite3.connect(DB_NAME) as conn:
c = conn.cursor()
c.execute('''CREATE TABLE items (name TEXT, checked INTEGER)''')
def add_item_to_db(self, name, checked=0):
with sqlite3.connect(DB_NAME) as conn:
c = conn.cursor()
c.execute("INSERT INTO items VALUES (?, ?)", (name, checked))
def get_items_from_db(self):
with sqlite3.connect(DB_NAME) as conn:
c = conn.cursor()
c.execute("SELECT * FROM items")
return [{
"name": row[0], "checked": bool(row[1])} for row in c.fetchall()]
def update_item_in_db(self, name, checked):
with sqlite3.connect(DB_NAME) as conn:
c = conn.cursor()
c.execute("UPDATE items SET checked = ? WHERE name = ?", (int(checked), name))
def delete_item_from_db(self, name):
with sqlite3.connect(DB_NAME) as conn:
c = conn.cursor()
c.execute("DELETE FROM items WHERE name = ?", (name,))
def add_item_to_list(self, e):
item_name = self.name_field.value
if item_name:
self.add_item_to_db(item_name)
self.items = self.get_items_from_db()
self.update_list_view()
self.name_field.value = ""
self.page.update()
def update_list_view(self):
self.items = self.get_items_from_db()
self.list_view.controls.clear()
for item in self.items:
checkbox = ft.Checkbox(value=item["checked"])
checkbox.on_change = lambda e, item=item: self.toggle_item_status(e, item)
# 创建一个居中的文本控件
centered_text = ft.Container(
content=ft.Text(item["name"], size=16),
alignment=ft.alignment.center,
expand=True
)
# 将复选框和文本放在一个水平行中
row = ft.Row(
controls=[
checkbox,
centered_text
],
alignment=ft.MainAxisAlignment.CENTER,
vertical_alignment=ft.CrossAxisAlignment.CENTER,
width=780 # 设置一个固定宽度,稍小于容器宽度
)
# 将行包装在一个容器中
item_container = ft.Container(
content=row,
alignment=ft.alignment.center,
width=800,
border=ft.border.all(1, ft.colors.GREY_400),
border_radius=5,
padding=5
)
self.list_view.controls.append(item_container)
self.page.update()
def update_data_table(self, e=None):
self.items = self.get_items_from_db()
self.data_table.rows.clear()
for item in self.items:
status = "已购买" if item["checked"] else "未购买"
self.data_table.rows.append(
ft.DataRow(cells=[ft.DataCell(ft.Text(item["name"])), ft.DataCell(ft.Text(status))])
)
self.page.update()
def toggle_item_status(self, e, item):
item["checked"] = e.control.value
self.update_item_in_db(item["name"], item["checked"])
self.page.update()
def delete_selected_items(self, e):
for item in self.items:
if item["checked"]:
self.delete_item_from_db(item["name"])
self.items = self.get_items_from_db()
self.update_list_view()
def tab_clicked(self, e):
tab_text = e.control.content.controls[1].controls[0].value
print(f"{
tab_text} 标签被点击")
if self.current_tab:
self.current_tab.bgcolor = PRIMARY_COLOR
self.current_tab = e.control
self.current_tab.bgcolor = SECONDARY_COLOR
self.page.update()
content_container = self.page.controls[0].content.controls[1]
content_container.clean()
content_container.controls.append(self.tab_contents[tab_text])
if tab_text == "我的选购":
self.update_list_view()
elif tab_text == "清单详情":
self.update_data_table()
self.page.update()
def create_app_title(self):
app_title_row = ft.Row(
controls=[
ft.IconButton(ft.icons.SHOPPING_CART, tooltip="购物车", icon_color=BG_COLOR),
ft.Text("购物清单助手桌面程序1.0", color=BG_COLOR, size=16)
],
alignment=ft.MainAxisAlignment.START
)
close_button = ft.IconButton(
ft.icons.CLOSE,
tooltip="关闭",
icon_color=ft.colors.RED,
on_click=lambda _: self.page.window.close()
)
icons_row = ft.Row(
controls=[
ft.IconButton(ft.icons.ADD, tooltip="添加", icon_color=ft.colors.GREEN, on_click=self.add_item_to_list),
ft.IconButton(ft.icons.HELP, tooltip="帮助", icon_color=ft.colors.BLUE, on_click=lambda _: print("帮助按钮点击")),
ft.IconButton(ft.icons.INFO, tooltip="关于", icon_color=ft.colors.RED, on_click=lambda _: print("关于按钮点击")),
close_button
],
alignment=ft.MainAxisAlignment.END
)
return ft.Container(
content=ft.Row(
controls=[app_title_row, icons_row],
alignment=ft.MainAxisAlignment.SPACE_BETWEEN,
height=50,
width=1200
),
bgcolor=PRIMARY_COLOR,
padding=10,
)
def create_tabs(self):
return ft.Row(
[
self.create_tab(text="我的选购", icon_path="gg.png", on_click=self.tab_clicked),
self.create_tab(text="清单详情", icon_path="hh.png", on_click=self.tab_clicked),
self.create_tab(text="添加商品", icon_path="ii.png", on_click=self.tab_clicked),
self.create_tab(text="保存商品", icon_path="jj.png", on_click=self.tab_clicked),
self.create_tab(text="删除商品", icon_path="kk.png", on_click=self.tab_clicked),
self.create_tab(text="联系我们", icon_path="ll.png", on_click=self.tab_clicked),
],
alignment=ft.MainAxisAlignment.START,
spacing=0,
width=1260
)
def create_tab(self, text, icon_path, on_click):
return ft.Container(
content=ft.Column(
controls=[
ft.Row(controls=[ft.Image(src=icon_path, width=64, height=64)], alignment=ft.MainAxisAlignment.CENTER),
ft.Row(controls=[ft.Text(text, color=BG_COLOR, size=16)], alignment=ft.MainAxisAlignment.CENTER)
],
alignment=ft.MainAxisAlignment.CENTER,
spacing=5
),
bgcolor=PRIMARY_COLOR,
height=200,
width=200,
on_click=on_click,
ink=True
)
def create_layout(self):
self.name_field = ft.TextField(label="请输入商品名称", width=500)
self.list_view = ft.ListView(expand=1, spacing=10, padding=10, auto_scroll=True)
self.data_table = ft.DataTable(
columns=[ft.DataColumn(ft.Text("商品名称")), ft.DataColumn(ft.Text("状态"))],
rows=[],
)
my_selections_content = ft.Container(
content=ft.Column(
controls=[
ft.Container(
height=100,
content=ft.Row(
controls=[
self.name_field,
ft.IconButton(ft.icons.ADD, tooltip="添加", icon_color=ft.colors.GREEN, on_click=self.add_item_to_list),
ft.IconButton(ft.icons.SAVE, tooltip="保存", icon_color=ft.colors.BLUE, on_click=self.update_data_table),
ft.IconButton(ft.icons.DELETE, tooltip="删除", icon_color=ft.colors.RED, on_click=self.delete_selected_items)
],
alignment=ft.MainAxisAlignment.CENTER
)
),
ft.Container(
content=self.list_view,
width=800,
height=400,
border=ft.border.all(1, ft.colors.GREY_400),
border_radius=5,
padding=10
)
],
spacing=10,
alignment=ft.MainAxisAlignment.START,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
),
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
)
contact_us_content = ft.Container(
content=ft.Column(
controls=[
ft.Container(
content=ft.Image(src="logo.jpg", width=200, height=200, fit=ft.ImageFit.COVER),
width=200, height=200, border_radius=100, clip_behavior=ft.ClipBehavior.ANTI_ALIAS, margin=50
),
ft.Text("购物清单助手桌面程序1.0", size=20, weight=ft.FontWeight.BOLD),
ft.Text("传奇开心果基于FLet创意编程", size=16),
ft.Text("2024年10月14日于瓜州家中完成作品", size=16),
],
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER,
spacing=20,
),
alignment=ft.alignment.center,
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
)
self.tab_contents = {
"我的选购": my_selections_content,
"清单详情": ft.Container(
content=ft.Column(
controls=[
ft.Container(content=ft.Text("商品清单", size=20, weight=ft.FontWeight.BOLD), alignment=ft.alignment.center),
ft.Container(
content=ft.ListView(
[
ft.Container(
content=self.data_table,
width=800,
)
],
expand=1,
spacing=10,
padding=20,
auto_scroll=True
),
width=800,
height=400,
border=ft.border.all(1, ft.colors.GREY_400),
border_radius=5,
)
],
spacing=20,
alignment=ft.MainAxisAlignment.CENTER,
horizontal_alignment=ft.CrossAxisAlignment.CENTER
),
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
),
"添加商品": ft.Container(
content=ft.Text("这是添加商品页面"),
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
alignment=ft.alignment.center
),
"保存商品": ft.Container(
content=ft.Text("这是保存商品页面"),
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
alignment=ft.alignment.center
),
"删除商品": ft.Container(
content=ft.Text("这是删除商品页面"),
width=1200,
height=522,
bgcolor=ft.colors.WHITE,
padding=10,
alignment=ft.alignment.center
),
"联系我们": contact_us_content,
}
return ft.Column(controls=[self.create_app_title(), self.create_tabs()], spacing=0)
def main(self, page: ft.Page):
self.page = page
self.init_db()
self.items = self.get_items_from_db()
self.page.window.width = WINDOW_WIDTH
self.page.window.height = WINDOW_HEIGHT
self.page.window.frameless = True
self.page.window.resizable = False
self.page.bgcolor = BG_COLOR
self.page.padding = 20
main_container = ft.Container(
content=ft.Column(spacing=0),
expand=True,
bgcolor=ft.colors.GREY_200,
border=ft.border.all(2, PRIMARY_COLOR),
padding=2
)
content_container = ft.Column()
layout_column = self.create_layout()
main_container.content.controls.extend([layout_column, content_container])
self.page.add(main_container)
# 默认选中"我的选购"标签并加载数据
self.current_tab = layout_column.controls[1].controls[0]
self.current_tab.bgcolor = SECONDARY_COLOR
content_container.controls.append(self.tab_contents["我的选购"])
self.update_list_view()
if __name__ == "__main__":
app = ShoppingListApp()
ft.app(target=app.main)
3. 解释说明
这个购物清单助手桌面程序有以下几个特色:
A. 界面设计美观:
使用了绿色主题,搭配白色背景,视觉效果清新。
采用了无边框设计(frameless),给人现代感。
顶部有应用标题和功能图标,布局合理。
B. 标签式导航:
使用了六个主要功能标签,每个标签都有图标和文字说明。
标签点击后会改变颜色,提供视觉反馈。
C. 数据持久化:
使用 SQLite 数据库存储购物清单项目,确保数据可以长期保存。
D. 功能丰富:
可以添加、删除、标记已购买的商品。
提供列表视图和表格视图两种方式展示购物清单。
支持批量删除已购买的商品。
E. 响应式设计:
窗口大小固定,但内部布局能够适应不同内容。
使用 ListView 实现长列表的滚动效果。
F. 自定义组件:
创建了自定义的标签组件,包含图标和文字。
商品列表项使用了自定义的容器设计,包括复选框和居中文本。
G. 模块化结构:
代码组织清晰,使用类的方式封装了应用的各个功能。
将不同页面的内容分别定义,便于管理和扩展。
H交互设计:
提供了添加、保存、删除等快捷操作按钮。
标签切换时有明显的视觉反馈。
I. 关于页面:
包含了一个圆形的 logo 图像和应用信息,体现了个性化设计。
J. 错误处理:
虽然代码中没有明确的错误处理机制,但基本的输入验证(如空输入检查)已经实现。
K. 可扩展性:
预留了"添加商品"、“保存商品”、"删除商品"等标签页面,为未来功能扩展做好了准备。
总结
总的来说,这个应用展示了如何使用 Flet 框架创建一个功能完整、界面美观的桌面应用程序。它结合了数据库操作、UI 设计和用户交互等多个方面,是一个很好的实践示例。
**4. 运行效果,截图为证 **
八、全文总结
这是我使用了Flet框架一段时间以后的反思顿悟,又是激情澎湃的文学表达,也是自主创新自定义控件创意编程灵感的舞蹈,也是循序渐进循循善诱通俗易懂雅俗共赏的Flet框架桌面程序开发教学教程,更是Flet框架触动灵魂的切身体验!也是我东临碣石,以观沧海心潮难平的胸臆抒怀!
我个人认为,flet打包安卓手机应用应该和谷歌和苹果公司合作定制一个专用移动应用打包工具,而且是图形化界面的这样才专业。才有利于flet框架在全球的快速普及。才不至于成为小众UI框架。星星之火,可以燎原,flet框架就是这样,有那么一天会风靡全球,这是我的预言。
背靠谷歌和苹果,大树底下好乘凉,生态很快就能成长起来。没有大动作,生态上成长不起来,就走不出小众UI框架的困局。