发布时间:2026/9/5 7:15:19
Python 基于 Tkinter 实现桌面电商购物系统 一、项目简介1.1 项目说明本项目使用 Python Tkinter 开发一款桌面版电商购物系统不需要连接数据库全部数据内存模拟实现。实现用户登录、商品浏览、加入购物车、购物车管理、结算下单、退出登录完整电商流程。适合 Python 课程设计、大作业、毕业设计练手。技术栈Python 3.xTkinterGUI 图形界面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: 酷睿i716G内存}, {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, padding30) main_frame.pack(expandTrue, filltk.BOTH) # 标题 title_label ttk.Label(main_frame, textPython电商购物系统, font(微软雅黑, 20, bold)) title_label.pack(pady(0, 30)) # 用户名行 user_frame ttk.Frame(main_frame) user_frame.pack(filltk.X, pady10) ttk.Label(user_frame, text用户名, font(微软雅黑, 12)).pack(sidetk.LEFT) self.username_var tk.StringVar() username_entry ttk.Entry(user_frame, textvariableself.username_var, font(微软雅黑, 12), width25) username_entry.pack(sidetk.LEFT, padx10) # 密码行 pwd_frame ttk.Frame(main_frame) pwd_frame.pack(filltk.X, pady10) ttk.Label(pwd_frame, text密 码, font(微软雅黑, 12)).pack(sidetk.LEFT) self.pwd_var tk.StringVar() pwd_entry ttk.Entry(pwd_frame, textvariableself.pwd_var, font(微软雅黑, 12), width25, show*) pwd_entry.pack(sidetk.LEFT, padx10) # 登录按钮 login_btn ttk.Button(main_frame, text登录, commandself.login) login_btn.pack(pady20) # 提示信息 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(filltk.X, padx10, pady10) # 购物车按钮 cart_btn ttk.Button(toolbar, text我的购物车, commandself.open_cart) cart_btn.pack(sidetk.RIGHT) # 退出按钮 exit_btn ttk.Button(toolbar, text退出登录, commandself.logout) exit_btn.pack(sidetk.RIGHT, padx10) # 商品表格 product_frame ttk.Frame(self) product_frame.pack(expandTrue, filltk.BOTH, padx10, pady10) # 表格列名 columns (ID, 商品名称, 价格(元), 分类, 描述) self.product_tree ttk.Treeview(product_frame, columnscolumns, showheadings, height15) # 设置列标题和宽度 for col in columns: self.product_tree.heading(col, textcol) if col 商品名称: self.product_tree.column(col, width200) elif col 描述: self.product_tree.column(col, width250) else: self.product_tree.column(col, width100) # 滚动条 scrollbar ttk.Scrollbar(product_frame, orienttk.VERTICAL, commandself.product_tree.yview) self.product_tree.configure(yscrollcommandscrollbar.set) # 布局表格和滚动条 self.product_tree.pack(sidetk.LEFT, expandTrue, filltk.BOTH) scrollbar.pack(sidetk.RIGHT, filltk.Y) # 加载商品数据 self.load_products() # 底部操作区 op_frame ttk.Frame(self) op_frame.pack(filltk.X, padx10, pady10) # 数量输入 ttk.Label(op_frame, text购买数量).pack(sidetk.LEFT) self.quantity_var tk.StringVar(value1) quantity_entry ttk.Entry(op_frame, textvariableself.quantity_var, width10) quantity_entry.pack(sidetk.LEFT, padx10) # 加入购物车按钮 add_cart_btn ttk.Button(op_frame, text加入购物车, commandself.add_to_cart) add_cart_btn.pack(sidetk.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, padding20) cart_frame.pack(expandTrue, filltk.BOTH) # 表格列名 columns (ID, 商品名称, 单价(元), 数量, 小计(元)) self.cart_tree ttk.Treeview(cart_frame, columnscolumns, showheadings, height10) # 设置列属性 for col in columns: self.cart_tree.heading(col, textcol) self.cart_tree.column(col, width120 if col 商品名称 else 80) # 滚动条 scrollbar ttk.Scrollbar(cart_frame, orienttk.VERTICAL, commandself.cart_tree.yview) self.cart_tree.configure(yscrollcommandscrollbar.set) # 布局表格 self.cart_tree.pack(sidetk.LEFT, expandTrue, filltk.BOTH) scrollbar.pack(sidetk.RIGHT, filltk.Y) # 底部操作区 bottom_frame ttk.Frame(self, padding0 20 20 20) bottom_frame.pack(filltk.X, anchortk.E) # 总价显示 self.total_var tk.StringVar(value总计¥0.00) total_label ttk.Label(bottom_frame, textvariableself.total_var, font(微软雅黑, 12, bold)) total_label.pack(sidetk.LEFT, padx20) # 操作按钮 clear_btn ttk.Button(bottom_frame, text清空购物车, commandself.clear_cart) clear_btn.pack(sidetk.LEFT, padx10) checkout_btn ttk.Button(bottom_frame, text结算下单, commandself.checkout) checkout_btn.pack(sidetk.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微软雅黑, size10) except: pass # 启动登录窗口 app LoginWindow() app.mainloop()四、运行说明4.1 运行环境Python 版本Python3.6 及以上TkinterPython 自带库无需 pip 安装第三方包如果 Linux 运行报错sudo apt install python3-tk4.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 图形化开发代码结构清晰面向对象设计适合课程设计学习。完整实现登录、商品浏览、购物车、下单整套电商基础流程没有复杂依赖开箱即用。

相关新闻

2026/9/5 7:10:18

电机拖动负载特性详解:恒转矩、恒功率、通风机类与选型要点

电机拖动必看:三种经典生产机械负载特性,搞懂它选型才不会翻车 干电机拖动这一行的朋友应该都有体会,很多现场问题——电机过热、启动困难、运行效率低、选型偏大或偏小——追根溯源,往往不是电机本身的质量问题,而是…

2026/9/5 7:10:18

STM32F103+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 9:45:27

自动排废机构中的接近开关:让废料离开正确路径

自动排废机构常用于冲切、模切、分切和裁边后的废料处理。废料如果没有被及时分离,可能混入成品区,也可能缠绕在输送通道中,影响下一次加工动作。很多产线不怕废料多,怕的是废料流向不清。接近开关在自动排废机构中通常用于确认排…

2026/9/5 9:45:27

Claude Code企业级实战:MCP协议与SubAgents架构深度解析

/* 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 9:45:27

接口调了4次都失败?Spring Boot任务状态与幂等性排查实战

/* 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 9:45:27

基于MATLAB ode45的斜齿轮10自由度动力学建模与振动分析实战

/* 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 9:45:27

Unity动态引擎声效开发:基于GE90涡扇发动机的3D音频实现方案

/* 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 2:46:54

vSound小提琴数字处理器实操指南:从接线到演出的完整配置

电小提琴或者原声小提琴插电演出,第一个绕不开的坎就是声音难听。原声琴的共鸣和空气感一旦进了拾音器,出来的往往是一坨干瘪、发尖、带着奇怪塑料味的信号。我当初第一次把琴接上乐队调音台,直接被主唱吐槽"你这声音像在锯钢丝"。…

2026/9/5 2:46:52

传感器接口IC如何攻克生物化学传感的微弱信号难题?

1. 从电极到比特流:为什么生物化学传感必须依赖专用接口IC 做生物化学传感的人都有过类似的经历:明明传感器本身性能很好,信号输出却一塌糊涂——噪声大、漂移明显、重复性差,怎么调都达不到预期。很多时候问题并不在传感器&#…

2026/9/5 2:44:34

STM32F411CEU6多通道ADC采集:扫描模式+DMA实现详解

1. 多通道 ADC 的用武之地把“Multichannel ADC”和“STM32F411CEU6”这两个关键字放在一起,其实就是嵌入式开发里最常遇到的一类需求:用一块不算贵的 MCU,同时采集多路模拟信号。STM32F411CEU6 是 48 引脚的 Cortex-M4F 主控,主频…

2026/9/5 0:04:47

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流

流式背压机制:避免前端渲染卡死与内存暴涨的滑动窗口限流在大模型流式输出(Streaming)与智能体实时推流的架构中,生产环境中经常出现一种“上下游生产消费速率严重失衡”的极端情况: 生产端极速产出:大模型…

2026/9/5 2:45:13

USB Type-C PCB布局分区设计:电源、高速信号与PD协议全攻略

做硬件这行,Type-C接口算是典型的“看着简单,做起来全坑”的东西。光引脚就24个,高低速信号、电源、控制线全部塞在一个小小的连接器里,如果PCB布局不做规划,打样回来基本就是“插上没反应”、“高速掉线”、“静电一打…

2026/9/5 2:30:42

系统编程学习原型如何补齐稳定性边界

系统编程学习原型如何补齐稳定性边界预算有限时&#xff0c;我先优化明显多余的复制&#xff0c;而不是猜测性地换容器。用借用传递只读数据通常就能减少分配&#xff1a; fn parse(line: &str) -> Result<Item, Error> { /* ... */ }用基准确认热点确实在分配&am…

2026/9/5 2:46:50

雨花区哪家财务公司代理记账比较好?

在雨花区&#xff0c;企业处理财税事务常常面临诸多挑战&#xff0c;选择一家靠谱的财务公司至关重要。湖南巨勤财务管理咨询有限公司就是本地正规实体财税服务机构&#xff0c;深耕本地工商财税行业多年&#xff0c;熟悉当地工商局、税务局最新政策与申报流程。主营公司注册、…