19
社区成员




完成搭建购物清单助手桌面程序框架的工作,二次开发有了脚手架和基本框架。开源发布,允许修改源代码二次开发,允许商业开发。
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)
这个购物清单助手桌面程序有以下几个特色:
1. 界面设计美观:
使用了绿色主题,搭配白色背景,视觉效果清新。
采用了无边框设计(frameless),给人现代感。
顶部有应用标题和功能图标,布局合理。
2. 标签式导航:
使用了六个主要功能标签,每个标签都有图标和文字说明。
标签点击后会改变颜色,提供视觉反馈。
3. 数据持久化:
使用 SQLite 数据库存储购物清单项目,确保数据可以长期保存。
4. 功能丰富:
可以添加、删除、标记已购买的商品。
提供列表视图和表格视图两种方式展示购物清单。
支持批量删除已购买的商品。
5. 响应式设计:
窗口大小固定,但内部布局能够适应不同内容。
使用 ListView 实现长列表的滚动效果。
6. 自定义组件:
创建了自定义的标签组件,包含图标和文字。
商品列表项使用了自定义的容器设计,包括复选框和居中文本。
7. 模块化结构:
代码组织清晰,使用类的方式封装了应用的各个功能。
将不同页面的内容分别定义,便于管理和扩展。
8. 交互设计:
提供了添加、保存、删除等快捷操作按钮。
标签切换时有明显的视觉反馈。
9. 关于页面:
包含了一个圆形的 logo 图像和应用信息,体现了个性化设计。
10. 错误处理:
虽然代码中没有明确的错误处理机制,但基本的输入验证(如空输入检查)已经实现。
11. 可扩展性:
预留了"添加商品"、"保存商品"、"删除商品"等标签页面,为未来功能扩展做好了准备。
总结
总的来说,这个应用展示了如何使用 Flet 框架创建一个功能完整、界面美观的桌面应用程序。它结合了数据库操作、UI 设计和用户交互等多个方面,是一个很好的实践示例。
效果图见文章最前面。漂亮美观。