news 2026/9/5 7:15:18

Python 基于 Tkinter 实现桌面电商购物系统

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Python 基于 Tkinter 实现桌面电商购物系统

一、项目简介

1.1 项目说明
本项目使用 Python + Tkinter 开发一款桌面版电商购物系统,不需要连接数据库,全部数据内存模拟实现。实现用户登录、商品浏览、加入购物车、购物车管理、结算下单、退出登录完整电商流程。适合 Python 课程设计、大作业、毕业设计练手。
技术栈:
Python 3.x
Tkinter(GUI 图形界面)
ttk 组件美化界面
decimal 高精度金额计算(避免浮点数精度 bug)
内存模拟用户库、商品库,无需 MySQL 数据库

1.2 实现功能清单
用户登录验证,内置两套测试账号
登录窗口居中,密码隐藏输入
商品列表表格展示:ID、商品名称、价格、分类、商品描述
选择商品,自定义购买数量加入购物车
独立购物车子窗口:展示商品、单价、数量、小计金额
清空购物车功能
结算下单,订单确认,下单成功清空购物车
退出登录,返回登录界面
窗口居中弹窗提示,消息框交互
使用 decimal 处理金额,解决浮点运算误差

1.3 测试账号

用户名密码昵称
admin123456系统管理员
user1111111普通用户

二、项目整体架构

项目采用面向对象编程,拆分多个类:
CartService:购物车业务逻辑服务类,纯粹业务,不操作 UI,实现添加、删除、清空、计算总价
LoginWindow:登录主窗口 (Tk)
MainWindow:系统主界面,商品展示页面 (Tk)
CartWindow:购物车弹窗 (Toplevel),子窗口
模拟内存数据库:USER_DB 用户字典,PRODUCTS商品列表

三、完整源代码

import tkinter as tk from tkinter import ttk, messagebox, simpledialog import decimal # ======================== 数据模型 ======================== # 模拟用户数据库 USER_DB = { "admin": {"password": "123456", "nickname": "系统管理员"}, "user1": {"password": "111111", "nickname": "普通用户"} } # 模拟商品数据库 PRODUCTS = [ {"id": 1, "name": "华为Mate70 Pro", "price": decimal.Decimal("6999.00"), "category": "手机", "desc": "鸿蒙系统,麒麟芯片"}, {"id": 2, "name": "苹果iPhone 16", "price": decimal.Decimal("7999.00"), "category": "手机", "desc": "A18芯片,iOS 18"}, {"id": 3, "name": "小米笔记本Pro 2025", "price": decimal.Decimal("5999.00"), "category": "电脑", "desc": "酷睿i7,16G内存"}, {"id": 4, "name": "华为平板MatePad Pro", "price": decimal.Decimal("2999.00"), "category": "平板", "desc": "12.6英寸,鸿蒙4.0"}, {"id": 5, "name": "AirPods Pro 2", "price": decimal.Decimal("1499.00"), "category": "耳机", "desc": "主动降噪,无线充电"} ] # ======================== 购物车服务类 ======================== class CartService: def __init__(self): self.cart_items = [] # 购物车项:[(product, quantity), ...] def add_to_cart(self, product, quantity): """添加商品到购物车(已存在则更新数量)""" if quantity <= 0: raise ValueError("购买数量必须大于0") # 检查商品是否已在购物车 for idx, (p, q) in enumerate(self.cart_items): if p["id"] == product["id"]: self.cart_items[idx] = (p, q + quantity) return # 新增商品到购物车 self.cart_items.append((product, quantity)) def remove_from_cart(self, product_id): """从购物车移除指定商品""" self.cart_items = [(p, q) for p, q in self.cart_items if p["id"] != product_id] def clear_cart(self): """清空购物车""" self.cart_items.clear() def get_cart_items(self): """获取购物车所有商品""" return self.cart_items.copy() def calculate_total(self): """计算购物车总金额""" total = decimal.Decimal("0.00") for product, quantity in self.cart_items: total += product["price"] * quantity return total def is_empty(self): """检查购物车是否为空""" return len(self.cart_items) == 0 # ======================== 登录窗口 ======================== class LoginWindow(tk.Tk): def __init__(self): super().__init__() self.title("电商系统 - 用户登录") self.geometry("450x350") self.resizable(False, False) self.center_window() # 窗口居中 # 初始化购物车服务 self.cart_service = CartService() # 创建UI self.create_ui() def center_window(self): """窗口居中显示""" self.update_idletasks() width = self.winfo_width() height = self.winfo_height() x = (self.winfo_screenwidth() // 2) - (width // 2) y = (self.winfo_screenheight() // 2) - (height // 2) self.geometry(f"{width}x{height}+{x}+{y}") def create_ui(self): """创建登录界面""" # 主面板 main_frame = ttk.Frame(self, padding="30") main_frame.pack(expand=True, fill=tk.BOTH) # 标题 title_label = ttk.Label(main_frame, text="Python电商购物系统", font=("微软雅黑", 20, "bold")) title_label.pack(pady=(0, 30)) # 用户名行 user_frame = ttk.Frame(main_frame) user_frame.pack(fill=tk.X, pady=10) ttk.Label(user_frame, text="用户名:", font=("微软雅黑", 12)).pack(side=tk.LEFT) self.username_var = tk.StringVar() username_entry = ttk.Entry(user_frame, textvariable=self.username_var, font=("微软雅黑", 12), width=25) username_entry.pack(side=tk.LEFT, padx=10) # 密码行 pwd_frame = ttk.Frame(main_frame) pwd_frame.pack(fill=tk.X, pady=10) ttk.Label(pwd_frame, text="密 码:", font=("微软雅黑", 12)).pack(side=tk.LEFT) self.pwd_var = tk.StringVar() pwd_entry = ttk.Entry(pwd_frame, textvariable=self.pwd_var, font=("微软雅黑", 12), width=25, show="*") pwd_entry.pack(side=tk.LEFT, padx=10) # 登录按钮 login_btn = ttk.Button(main_frame, text="登录", command=self.login) login_btn.pack(pady=20) # 提示信息 tip_label = ttk.Label(main_frame, text="测试账号:admin/123456 | user1/111111", font=("微软雅黑", 10)) tip_label.pack() def login(self): """处理登录逻辑""" username = self.username_var.get().strip() password = self.pwd_var.get().strip() # 验证输入 if not username: messagebox.showerror("错误", "请输入用户名!") return if not password: messagebox.showerror("错误", "请输入密码!") return # 验证用户 user = USER_DB.get(username) if not user or user["password"] != password: messagebox.showerror("错误", "用户名或密码错误!") self.pwd_var.set("") # 清空密码框 return # 登录成功,打开主窗口 messagebox.showinfo("成功", f"登录成功!欢迎您,{user['nickname']}!") self.destroy() # 关闭登录窗口 MainWindow(user, self.cart_service).mainloop() # ======================== 主窗口(商品展示) ======================== class MainWindow(tk.Tk): def __init__(self, user, cart_service): super().__init__() self.title(f"电商系统 - {user['nickname']}") self.geometry("900x600") self.resizable(True, True) self.center_window() # 初始化数据 self.current_user = user self.cart_service = cart_service self.cart_window = None # 购物车窗体引用 # 创建UI self.create_ui() def center_window(self): """窗口居中""" self.update_idletasks() width = self.winfo_width() height = self.winfo_height() x = (self.winfo_screenwidth() // 2) - (width // 2) y = (self.winfo_screenheight() // 2) - (height // 2) self.geometry(f"{width}x{height}+{x}+{y}") def create_ui(self): """创建主界面""" # 顶部工具栏 toolbar = ttk.Frame(self) toolbar.pack(fill=tk.X, padx=10, pady=10) # 购物车按钮 cart_btn = ttk.Button(toolbar, text="我的购物车", command=self.open_cart) cart_btn.pack(side=tk.RIGHT) # 退出按钮 exit_btn = ttk.Button(toolbar, text="退出登录", command=self.logout) exit_btn.pack(side=tk.RIGHT, padx=10) # 商品表格 product_frame = ttk.Frame(self) product_frame.pack(expand=True, fill=tk.BOTH, padx=10, pady=10) # 表格列名 columns = ("ID", "商品名称", "价格(元)", "分类", "描述") self.product_tree = ttk.Treeview(product_frame, columns=columns, show="headings", height=15) # 设置列标题和宽度 for col in columns: self.product_tree.heading(col, text=col) if col == "商品名称": self.product_tree.column(col, width=200) elif col == "描述": self.product_tree.column(col, width=250) else: self.product_tree.column(col, width=100) # 滚动条 scrollbar = ttk.Scrollbar(product_frame, orient=tk.VERTICAL, command=self.product_tree.yview) self.product_tree.configure(yscrollcommand=scrollbar.set) # 布局表格和滚动条 self.product_tree.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 加载商品数据 self.load_products() # 底部操作区 op_frame = ttk.Frame(self) op_frame.pack(fill=tk.X, padx=10, pady=10) # 数量输入 ttk.Label(op_frame, text="购买数量:").pack(side=tk.LEFT) self.quantity_var = tk.StringVar(value="1") quantity_entry = ttk.Entry(op_frame, textvariable=self.quantity_var, width=10) quantity_entry.pack(side=tk.LEFT, padx=10) # 加入购物车按钮 add_cart_btn = ttk.Button(op_frame, text="加入购物车", command=self.add_to_cart) add_cart_btn.pack(side=tk.LEFT) def load_products(self): """加载商品数据到表格""" # 清空现有数据 for item in self.product_tree.get_children(): self.product_tree.delete(item) # 添加商品 for product in PRODUCTS: self.product_tree.insert("", tk.END, values=( product["id"], product["name"], f"{product['price']:.2f}", product["category"], product["desc"] )) def add_to_cart(self): """添加选中商品到购物车""" # 获取选中行 selected_items = self.product_tree.selection() if not selected_items: messagebox.showwarning("提示", "请先选择要购买的商品!") return # 获取数量 try: quantity = int(self.quantity_var.get().strip()) if quantity <= 0: messagebox.showerror("错误", "购买数量必须大于0!") return except ValueError: messagebox.showerror("错误", "请输入有效的数字!") return # 获取选中商品 selected_item = selected_items[0] product_id = int(self.product_tree.item(selected_item, "values")[0]) product = next(p for p in PRODUCTS if p["id"] == product_id) # 添加到购物车 try: self.cart_service.add_to_cart(product, quantity) messagebox.showinfo("成功", f"{product['name']} 已加入购物车!") except ValueError as e: messagebox.showerror("错误", str(e)) def open_cart(self): """打开购物车窗体""" if self.cart_window is None or not self.cart_window.winfo_exists(): self.cart_window = CartWindow(self, self.cart_service) self.cart_window.lift() # 置于顶层 def logout(self): """退出登录""" if messagebox.askyesno("确认", "确定要退出登录吗?"): self.destroy() LoginWindow().mainloop() # ======================== 购物车窗体 ======================== class CartWindow(tk.Toplevel): def __init__(self, parent, cart_service): super().__init__(parent) self.title("我的购物车") self.geometry("700x400") self.resizable(False, False) self.center_window() # 初始化数据 self.cart_service = cart_service # 创建UI self.create_ui() self.update_cart() def center_window(self): """窗口居中""" self.update_idletasks() width = self.winfo_width() height = self.winfo_height() x = (self.winfo_screenwidth() // 2) - (width // 2) y = (self.winfo_screenheight() // 2) - (height // 2) self.geometry(f"{width}x{height}+{x}+{y}") def create_ui(self): """创建购物车界面""" # 购物车表格 cart_frame = ttk.Frame(self, padding="20") cart_frame.pack(expand=True, fill=tk.BOTH) # 表格列名 columns = ("ID", "商品名称", "单价(元)", "数量", "小计(元)") self.cart_tree = ttk.Treeview(cart_frame, columns=columns, show="headings", height=10) # 设置列属性 for col in columns: self.cart_tree.heading(col, text=col) self.cart_tree.column(col, width=120 if col == "商品名称" else 80) # 滚动条 scrollbar = ttk.Scrollbar(cart_frame, orient=tk.VERTICAL, command=self.cart_tree.yview) self.cart_tree.configure(yscrollcommand=scrollbar.set) # 布局表格 self.cart_tree.pack(side=tk.LEFT, expand=True, fill=tk.BOTH) scrollbar.pack(side=tk.RIGHT, fill=tk.Y) # 底部操作区 bottom_frame = ttk.Frame(self, padding="0 20 20 20") bottom_frame.pack(fill=tk.X, anchor=tk.E) # 总价显示 self.total_var = tk.StringVar(value="总计:¥0.00") total_label = ttk.Label(bottom_frame, textvariable=self.total_var, font=("微软雅黑", 12, "bold")) total_label.pack(side=tk.LEFT, padx=20) # 操作按钮 clear_btn = ttk.Button(bottom_frame, text="清空购物车", command=self.clear_cart) clear_btn.pack(side=tk.LEFT, padx=10) checkout_btn = ttk.Button(bottom_frame, text="结算下单", command=self.checkout) checkout_btn.pack(side=tk.LEFT) def update_cart(self): """更新购物车数据""" # 清空表格 for item in self.cart_tree.get_children(): self.cart_tree.delete(item) # 加载购物车数据 cart_items = self.cart_service.get_cart_items() for product, quantity in cart_items: subtotal = product["price"] * quantity self.cart_tree.insert("", tk.END, values=( product["id"], product["name"], f"{product['price']:.2f}", quantity, f"{subtotal:.2f}" )) # 更新总价 total = self.cart_service.calculate_total() self.total_var.set(f"总计:¥{total:.2f}") def clear_cart(self): """清空购物车""" if self.cart_service.is_empty(): messagebox.showinfo("提示", "购物车已为空!") return if messagebox.askyesno("确认", "确定要清空购物车吗?"): self.cart_service.clear_cart() self.update_cart() messagebox.showinfo("成功", "购物车已清空!") def checkout(self): """结算下单""" if self.cart_service.is_empty(): messagebox.showerror("错误", "购物车为空,无法结算!") return total = self.cart_service.calculate_total() if messagebox.askyesno("结算确认", f"确认下单?\n订单总金额:¥{total:.2f}"): messagebox.showinfo("下单成功", f"订单创建成功!\n支付金额:¥{total:.2f}\n感谢您的购买!") self.cart_service.clear_cart() self.update_cart() self.destroy() # 关闭购物车 # ======================== 程序入口 ======================== if __name__ == "__main__": # 设置tkinter字体(解决中文显示问题) try: tk.font.nametofont("TkDefaultFont").configure(family="微软雅黑", size=10) except: pass # 启动登录窗口 app = LoginWindow() app.mainloop()

四、运行说明

4.1 运行环境
Python 版本:Python3.6 及以上
Tkinter:Python 自带库,无需 pip 安装第三方包
如果 Linux 运行报错:sudo apt install python3-tk
4.2 运行步骤
将全部代码复制保存为 e_shop.py
直接运行脚本
在登录界面输入测试账号密码登录
在商品列表选中商品,输入购买数量,点击加入购物车
点击我的购物车打开弹窗,可以查看、清空、结算订单
退出登录回到登录页面

五、核心模块讲解
5.1 CartService 购物车服务类
业务逻辑层,和界面解耦。
add_to_cart() 添加商品到购物车,重复商品累加数量
calculate_total() 使用 decimal 计算总价,规避浮点数精度问题
clear_cart() 清空购物车
后续如果改成数据库版本,只需要修改这个类,GUI 代码几乎不用改动。
5.2 登录窗口 LoginWindow
程序入口窗口,校验用户名密码,登录成功销毁自己,打开主窗口 MainWindow。
5.3 MainWindow 商品主界面
使用ttk.Treeview表格组件展示全部商品;选中商品设置数量加入购物车,可以唤起购物车子窗口,支持退出登录。
5.4 CartWindow 购物车子窗口
继承tk.Toplevel,属于模态子弹窗;实时渲染购物车列表,计算小计、总金额,实现清空购物车、下单结算。
六、项目不足与扩展方向
本项目内存存储,关闭程序所有数据丢失,可以扩展:
JSON 文件持久化保存用户、商品、订单数据
新增用户注册功能
购物车支持单独删除某一件商品
订单历史记录查看
商品分类筛选搜索框
管理员后台:新增、修改、删除商品
对接 SQLite 数据库替代内存模拟数据
七、总结
本电商系统基于 Tkinter 图形化开发,代码结构清晰,面向对象设计,适合课程设计学习。完整实现登录、商品浏览、购物车、下单整套电商基础流程,没有复杂依赖,开箱即用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/5 7:14:03

Embedding 有哪几种算法?

一、 Embedding 的核心本质与表征范式在信息检索、自然语言处理&#xff08;NLP&#xff09;以及大模型检索增强生成&#xff08;RAG&#xff09;系统中&#xff0c;计算机无法直接理解人类的自然语言字符。Embedding 算法充当了自然语言与高维几何计算之间的数学翻译器。1. 向…

作者头像 李华
网站建设 2026/9/5 7:13:25

我带着DeepSeek Harness跑了一周真实需求——这份避坑速查表请收好

开源第一天我就上手了 DeepSeek Harness&#xff0c;结论是&#xff1a;它和 Claude Code 的差距比想象中大。截止今天&#xff0c;这个结论我没改&#xff0c;但我把踩过的坑、还有社区里天天有人问的坑&#xff0c;整理成了一份速查表。装之前先看这篇&#xff0c;能省你半天…

作者头像 李华
网站建设 2026/9/5 7:06:44

裸机转RTOS快速迁移实战:基于FreeRTOS的任务划分与队列通信

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:06:39

AI安全测试双刃剑:从Artifactory零日漏洞看智能攻防新范式

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/5 7:06:21

计算机毕业设计之基于JavaWeb的中药信息管理系统的设计与实现

如今&#xff0c;在科学技术飞速发展的情况下&#xff0c;信息化的时代也已因为计算机的出现而来临&#xff0c;信息化也已经影响到了社会上的各个方面。它可以为人们提供许多便利之处&#xff0c;可以大大提高人们的工作效率。随着计算机技术的发展的普及&#xff0c;各个领域…

作者头像 李华