使用Flet开发的购物清单助手桌面程序v1.0脚手架和基本框架源代码开源发布,IDE运行和调试通过

传奇开心果编程
Python领域优质创作者
2024-10-15 10:14:42

img

img

img

一、编程思路

完成搭建购物清单助手桌面程序框架的工作,二次开发有了脚手架和基本框架。开源发布,允许修改源代码二次开发,允许商业开发。

二、示例代码


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 设计和用户交互等多个方面,是一个很好的实践示例。

四、运行效果,截图为证

效果图见文章最前面。漂亮美观。

...全文
137 回复 打赏 收藏 转发到动态 举报
AI 作业
写回复
用AI写文章
回复
切换为时间正序
请发表友善的回复…
发表回复

19

社区成员

发帖
与我相关
我的任务
社区描述
近期,感兴趣Ant Design Mobile of React、Vant of Vue 、MUI of h5App、WeUI 原生微信小程序和beeware移动应用开发,发布原创博文创建专栏发布动态
androidios微信小程序 个人社区 甘肃省·酒泉市
社区管理员
  • 传奇开心果编程
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧