随着社会的发展,为了满足人们的生活需求,大街小巷出现了越来越多的综合型超市,这些超市为我们的生活提供了极大的便利。超市每天都会有数以百计的商品进进出出,库存在不断变化,销售数据每天都在增加,为了更好地管理超市,利用Python可以快速构建一个智能的进销存管理系统。
1、超市进销存管理系统介绍
Python作为目前最为流行和实用的编程语言之一,广泛应用于各类信息管理系统设计,可以帮助我们有效地存储、检索、管理和分析数据。本节教程将介绍如何使用Python的Tkinter库结合SQLite3数据库来设计一个超市进销存管理系统。其中,Python的Tkinter库提供了直观的GUI图形用户界面,而SQLite3是一个轻量级的数据库系统,适合小型应用,无需安装和配置,开箱即用。
本系统分为管理员和员工两个角色,员工账号登录系统后可以查看员工的个人信息、商品信息和采购信息;管理员账号登录系统后,有权限编辑所有的信息,包括添加、修改、删除和导出信息等功能,支持将信息列表中的数据导出到Excel文件中。注意:管理员默认账号为“admin”,密码为“admin123”。员工账号默认为员工的工号,密码为“123456”。每次添加新员工信息时,数据库会自动创建新的员工账号,新员工账号默认为新员工的工号,密码默认为“123456”。每次添加新的员工信息后,即可通过新工号登录系统,查看新员工个人的信息。
首次启动该系统时,会在当前脚本工作目录下创建一个名为“manage.db”的数据库文件,并自动在数据库文件中创建名为“users”、“employee”和“commodity”三个数据库表,用于保存账号信息、员工信息和商品信息,系统默认会向users表中插入一个管理员账号和两个员工账号信息,员工账号默认为员工的工号。系统同样默认会向employee和commodity两个表中分别插入两条完整的员工信息和商品信息,以供参考。
在信息列表中,通过右击鼠标可以删除单条信息,也可以点击界面中的“删除”按钮,删除指定信息。在信息列表中还可以通过左键双击鼠标,直接打开修改信息的页面,也可以点击界面中的“修改”按钮,修改指定信息。
2、超市进销存管理系统界面演示
3、代码实现
(1)安装pandas库
首先,确保你已经安装了pandas库。如果还没有安装,可以通过pip安装:
pip install pandas
(2)超市进销存管理系统,完整代码如下所示:
动手练一练:
import os, pandas, sqlite3, webbrowser
import tkinter as tk
from tkinter import ttk, messagebox, filedialog
# 获取当前脚本文件所在的目录
script_directory = os.path.dirname(os.path.abspath(__file__))
# 将当前脚本文件所在的目录设置为工作目录
os.chdir(script_directory)
database_file = "manage.db" # 定义数据库文件为“manage.db”
admin_name = "admin" # 定义管理员登录账号为“admin”
admin_password = "admin123" # 定义管理员登录密码为“admin123”
employee_password = "123456" # 定义员工登录密码为“123456”
# 连接到数据库(如果数据库不存在,则会自动创建)
try:
if not os.path.exists(database_file):
# 创建数据库连接,插入测试数据
def create_db():
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
connection = conn.cursor()
# 创建账号表,用于存储账号和密码
connection.execute('''
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
username TEXT UNIQUE NOT NULL,
password TEXT NOT NULL,
category TEXT NOT NULL CHECK(category IN ('employee', 'admin'))
)''')
# 创建员工信息表
connection.execute('''
CREATE TABLE IF NOT EXISTS employee (
Enumber TEXT PRIMARY KEY,
Ename TEXT NOT NULL,
Egender TEXT NOT NULL,
Eage TEXT NOT NULL,
Edepartment TEXT NOT NULL,
Eposition TEXT NOT NULL,
Emobile TEXT NOT NULL)
''')
# 添加测试账号和密码,包括一个管理员账号和2个员工账号
users_data = [
(admin_name, admin_password, 'admin'),
('123', employee_password, 'employee'),
('456', employee_password, 'employee')
]
# 使用元组列表将默认的账号和密码插入users表中
connection.executemany('INSERT INTO users (username, password, category) VALUES (?, ?, ?)', users_data)
# 添加测试员工数据
employee_data = [
('123', '张三', '男', '25', '财务部', '会计', '123456789'),
('456', '李四', '女', '30', '销售部', '理货员', '123456789')
]
# 使用元组列表将默认的员工信息插入employee表中
connection.executemany('INSERT INTO employee VALUES (?, ?, ?, ?, ?, ?, ?)', employee_data)
# 创建商品信息表
connection.execute('''
CREATE TABLE IF NOT EXISTS commodity (
Cnumber TEXT PRIMARY KEY,
Cname TEXT NOT NULL,
Ccategory TEXT NOT NULL,
Cprice TEXT NOT NULL,
Cspecifications TEXT NOT NULL,
Csupplier TEXT NOT NULL,
Cinventory TEXT NOT NULL)
''')
# 添加测试商品数据
commodity_data = [
('1', '苹果', '水果', '5', '大', 'xx供应商', '100kg'),
('2', '土豆', '蔬菜', '5', '小', 'xx供应商', '100kg')
]
# 使用元组列表将默认的商品信息插入commodity表中
connection.executemany('INSERT INTO commodity VALUES (?, ?, ?, ?, ?, ?, ?)', commodity_data)
conn.commit() # 提交事务以保存数据库的更改
conn.close() # 关闭连接
# 执行插入数据
create_db()
except:
pass
# 定义成功提示框
def show_sucess(window, txt):
add = tk.Toplevel(window)
add.title("成功")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 240
height = 100
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text=f'{txt}', font=('黑体', 14)).pack(pady=10)
def confirmm():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).pack(pady=10)
# 定义错误提示框
def show_error(window, txt):
add = tk.Toplevel(window)
add.title("错误")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 240
height = 100
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text=f'{txt}', font=('黑体', 14)).pack(pady=10)
def confirmm():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).pack(pady=10)
# 定义信息提示框
def show_info(window, txt):
add = tk.Toplevel(window)
add.title("提示")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 500
height = 100
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text=f'{txt}', font=('黑体', 14)).pack(pady=10)
def confirmm():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).pack(pady=10)
# 验证用户账号登录操作
def check_user(username, password):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT username, category FROM users WHERE username=? AND password=?",
(username, password)
)
result = cursor.fetchone()
conn.close() # 关闭连接
if result:
return {'success': True, 'username': result[0], 'category': result[1]}
return {'success': False, 'message': '用户名或密码错误'}
# 添加新员工信息时,自动创建新员工账号
def add_user(username, password, category):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"INSERT INTO users (username, password, category) VALUES (?, ?, ?)",
(username, password, category)
)
conn.commit() # 提交事务以保存数据库的更改
return True
conn.close() # 关闭连接
# 从数据库中获取所有的员工信息
def search_all_employee():
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM employee")
columns = [column[0] for column in cursor.description]
employee = [dict(zip(columns, row)) for row in cursor.fetchall()]
conn.commit() # 提交事务以保存数据库的更改
return employee
conn.close() # 关闭连接
# 根据工号获取员工信息
def search_employee_id(employee_id):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM employee WHERE Enumber=?", (employee_id,))
columns = [column[0] for column in cursor.description]
employee = cursor.fetchone()
conn.commit() # 提交事务以保存数据库的更改
return dict(zip(columns, employee)) if employee else None
conn.close() # 关闭连接
# 根据工号或者员工姓名搜索员工信息
def search_employee(keyword):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT * FROM employee WHERE Enumber LIKE ? OR Ename LIKE ?",
(f'%{keyword}%', f'%{keyword}%')
)
columns = [column[0] for column in cursor.description]
employee = [dict(zip(columns, row)) for row in cursor.fetchall()]
return employee
conn.close() # 关闭连接
# 添加员工信息
def add_employee(employee_data):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"INSERT INTO employee VALUES (?, ?, ?, ?, ?, ?, ?)",
(
employee_data['Enumber'],
employee_data['Ename'],
employee_data['Egender'],
employee_data['Eage'],
employee_data['Edepartment'],
employee_data['Eposition'],
employee_data['Emobile'],
)
)
conn.commit() # 提交事务以保存数据库的更改
return True
conn.close() # 关闭连接
# 更新员工信息
def update_employee(employee_id, new_data):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
# 创建更新语句
set_clause = []
params = []
for field, value in new_data.items():
set_clause.append(f"{field}=?")
params.append(value)
params.append(employee_id)
cursor.execute(
f"UPDATE employee SET {', '.join(set_clause)} WHERE Enumber=?",
params
)
conn.commit() # 提交事务以保存数据库的更改
return cursor.rowcount > 0
conn.close() # 关闭连接
# 删除员工信息,同时删除保存的登录账号
def delete_employee(employee_id):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM employee WHERE Enumber=?", (employee_id,))
cursor.execute("DELETE FROM users WHERE username=?", (employee_id,))
conn.commit() # 提交事务以保存数据库的更改
return cursor.rowcount > 0
conn.close() # 关闭连接
# 从数据库中获取所有的商品信息
def search_all_commodity():
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM commodity")
columns = [column[0] for column in cursor.description]
commodity = [dict(zip(columns, row)) for row in cursor.fetchall()]
conn.commit() # 提交事务以保存数据库的更改
return commodity
conn.close() # 关闭连接
# 根据商品编号获取商品信息
def search_commodity_id(commodity_id):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("SELECT * FROM commodity WHERE Cnumber=?", (commodity_id,))
columns = [column[0] for column in cursor.description]
commodity = cursor.fetchone()
conn.commit() # 提交事务以保存数据库的更改
return dict(zip(columns, commodity)) if commodity else None
conn.close() # 关闭连接
# 根据商品编号或者商品名称搜索商品信息
def search_commodity(keyword):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"SELECT * FROM commodity WHERE Cnumber LIKE ? OR Cname LIKE ?",
(f'%{keyword}%', f'%{keyword}%')
)
columns = [column[0] for column in cursor.description]
commodity = [dict(zip(columns, row)) for row in cursor.fetchall()]
return commodity
conn.close() # 关闭连接
# 添加商品信息
def add_commodity(commodity_data):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute(
"INSERT INTO commodity VALUES (?, ?, ?, ?, ?, ?, ?)",
(
commodity_data['Cnumber'],
commodity_data['Cname'],
commodity_data['Ccategory'],
commodity_data['Cprice'],
commodity_data['Cspecifications'],
commodity_data['Csupplier'],
commodity_data['Cinventory'],
)
)
conn.commit() # 提交事务以保存数据库的更改
return True
conn.close() # 关闭连接
# 更新商品信息
def update_commodity(commodity_id, new_data):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
# 创建更新语句
set_clause = []
params = []
for field, value in new_data.items():
set_clause.append(f"{field}=?")
params.append(value)
params.append(commodity_id)
cursor.execute(
f"UPDATE commodity SET {', '.join(set_clause)} WHERE Cnumber=?",
params
)
conn.commit() # 提交事务以保存数据库的更改
return cursor.rowcount > 0
conn.close() # 关闭连接
# 删除商品信息
def delete_commodity(commodity_id):
# 使用with语句自动管理数据库连接的生命周期
with sqlite3.connect(database_file) as conn:
cursor = conn.cursor()
cursor.execute("DELETE FROM commodity WHERE Cnumber=?", (commodity_id,))
conn.commit() # 提交事务以保存数据库的更改
return cursor.rowcount > 0
conn.close() # 关闭连接
# 定义管理类,处理数据的增、删、改、查
class ControlData:
# 添加员工信息
def add_employee(self, employee_data):
# 添加新员工信息时,自动创建新员工账号
add_user(employee_data['Enumber'], employee_password, 'employee')
return add_employee(employee_data)
# 获取所有员工信息
def search_all_employee(self):
return search_all_employee()
# 根据工号获取员工信息
def search_employee_id(self, employee_id):
return search_employee_id(employee_id)
# 根据工号或姓名搜索员工
def search_employee(self, keyword):
return search_employee(keyword)
# 更新员工信息
def update_employee(self, employee_id, new_data):
return update_employee(employee_id, new_data)
# 删除员工信息
def delete_employee(self, employee_id):
return delete_employee(employee_id)
# 添加商品信息
def add_commodity(self, commodity_data):
return add_commodity(commodity_data)
# 获取所有商品信息
def search_all_commodity(self):
return search_all_commodity()
# 根据商品编号获取商品信息
def search_commodity_id(self, commodity_id):
return search_commodity_id(commodity_id)
# 根据商品编号或商品名称搜索商品
def search_commodity(self, keyword):
return search_commodity(keyword)
# 更新商品信息
def update_commodity(self, commodity_id, new_data):
return update_commodity(commodity_id, new_data)
# 删除商品信息
def delete_commodity(self, commodity_id):
return delete_commodity(commodity_id)
# 定义用户账号管理类,处理用户登录和权限
class Users:
# 验证用户登录
def authenticate(self, username, password):
return check_user(username, password)
# 添加新用户
def add_user(self, username, password, category):
return add_user(username, password, category)
# 定义登录窗口页面
class UserLogin:
def __init__(self, success_login):
self.success_login = success_login
self.user_manager = Users()
self.app = tk.Tk()
self.app.title("超市进销存管理系统 - 登录")
# 设置窗口背景颜色
self.app.config(bg='#95e8fd')
# 设置窗口居中
window_width = 500
window_height = 340
screen_width = self.app.winfo_screenwidth()
screen_height = self.app.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.app.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.app.resizable(width=False, height=False)
# 主界面创
self.main_widgets()
# 创建登录界面控件
def main_widgets(self):
# 鼠标点击时,清除Entry控件中的提示信息
def on_entry_click(event):
if event.widget.get() == '请输入用户名' or event.widget.get() == '请输入密码':
event.widget.delete(0, tk.END) # 删除默认文本
event.widget.config(fg='black') # 更改文本颜色为黑色
# 鼠标离开时,在Entry控件中显示提示信息
def on_focus_out(event):
if event.widget.get() == '':
if event.widget == self.username_entry:
event.widget.insert(0, '请输入用户名')
elif event.widget == self.password_entry:
event.widget.insert(0, '请输入密码')
event.widget.config(fg='gray') # 更改文本颜色为灰色
# 在上面放置标题
label1 = tk.Label(self.app, text='欢迎使用', font=('宋体', 20, 'bold'), bg='#95e8fd', justify=tk.CENTER)
label1.place(x = 60, y = 20, width = 400, height = 50)
label2 = tk.Label(self.app, text='超市进销存管理系统', font=('宋体', 20, 'bold'), bg='#95e8fd', justify=tk.CENTER)
label2.place(x = 50, y = 80, width = 400, height = 50)
# 在下面设计登录窗口
tk.Label(self.app, text="用户名:", font = ('宋体', 15), width = 15, bg='#95e8fd').place(x = 65, y = 160, anchor = 'nw')
self.username_entry = tk.Entry(self.app, highlightthickness=1, font=('宋体', 15), bg = "white", width=20)
self.username_entry.place(x = 190, y = 160, anchor = 'nw')
self.username_entry.insert(0, '请输入用户名') # 插入默认文本
self.username_entry.config(fg='gray') # 设置文本颜色为灰色
self.username_entry.bind('<FocusIn>', on_entry_click)
self.username_entry.bind('<FocusOut>', on_focus_out)
tk.Label(self.app, text="密码:", font = ('宋体', 15), width = 15, bg='#95e8fd').place(x = 65, y = 210, anchor = 'nw')
self.password_entry = tk.Entry(self.app, highlightthickness=1,font=('宋体', 15), bg = "white", width=20)
self.password_entry.place(x = 190, y = 210, anchor = 'nw')
self.password_entry.insert(0, '请输入密码') # 插入默认文本
self.password_entry.config(fg='gray') # 设置文本颜色为灰色
self.password_entry.bind('<FocusIn>', on_entry_click)
self.password_entry.bind('<FocusOut>', on_focus_out)
button_login = tk.Button(self.app, text="登录", font=('宋体', 15), bg="#56cdff", width=20, command=self.login)
button_login.place(x = 150, y = 270, anchor = 'nw')
# 检查输入的账号和密码是否正确
def login(self):
username = self.username_entry.get().strip()
password = self.password_entry.get().strip()
# 判断输入的用户名和密码不能为空
if not username or not password:
messagebox.showerror("错误", "用户名和密码不能为空!")
return
result = self.user_manager.authenticate(username, password)
if result['success']:
messagebox.showinfo(title="登录成功", message=f"欢迎登录超市进销存管理系统,{username}!")
self.app.destroy()
self.success_login(result['username'], result['category'])
else:
messagebox.showerror("错误", result['message'])
# 显示登录窗口
def run(self):
self.app.mainloop()
# 员工登录界面,每个员工只能查看自己的个人信息、商品信息和采购信息
class EmployWindow:
def __init__(self, username):
self.username = username
self.manager_control = ControlData()
self.app = tk.Tk()
self.app.title(f"超市进销存管理系统-{username}员工登录")
# 设置窗口居中
window_width = 880
window_height = 400
screen_width = self.app.winfo_screenwidth()
screen_height = self.app.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.app.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.app.resizable(width=False, height=False)
# 窗口样式配置
self.style = ttk.Style()
self.set_styles()
# 简单映射
self.employee_id = username
self.main_widgets()
# 定义样式函数
def set_styles(self):
# 设置主题为clam
self.style.theme_use('clam')
# 组件基础样式配置
self.style.configure('TFrame', background='#F3F3F3')
self.style.configure('TLabel', background='#F3F3F3',
foreground='#605E5C')
self.style.configure('TEntry', fieldbackground='#FFFFFF',
bordercolor='#CCCCCC', relief='solid')
self.style.configure('TButton', padding=3, relief='flat',
background='#0078D4',
font=('宋体', 12),
foreground='white')
self.style.map('TButton',
background=[('active', '#004da3'), ('disabled', '#E0E0E0')],
foreground=[('disabled', '#A0A0A0')])
self.style.configure('TLabelframe', bordercolor='#D0D0D0',
relief='groove', padding=10, background='#F3F3F3')
self.style.configure('TLabelframe.Label', padding=10, foreground='#0078D4', font=('宋体', 14, 'bold'), background='#F3F3F3')
# 创建员工界面控件
def main_widgets(self):
# 主框架
main_frame = tk.Frame(self.app)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 左侧信息面板
information_frame = ttk.LabelFrame(main_frame, text=f"{self.username}-员工个人信息")
information_frame.pack(side=tk.LEFT, fill=tk.Y, padx=5, pady=5)
# 获取员工信息
employee_data = self.manager_control.search_employee_id(self.employee_id)
if not employee_data:
show_error(self.app, "找不到对应的员工信息!")
self.app.destroy()
return
# 显示员工信息
tk.Label(information_frame, text=f"工号: {employee_data['Enumber']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"姓名: {employee_data['Ename']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"性别: {employee_data['Egender']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"年龄: {employee_data['Eage']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"部门: {employee_data['Edepartment']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"职务: {employee_data['Eposition']}").pack(anchor=tk.W, pady=5)
tk.Label(information_frame, text=f"手机号码: {employee_data['Emobile']}").pack(anchor=tk.W, pady=5)
# 右侧功能面板
view_frame = tk.Frame(main_frame)
view_frame.pack(side=tk.RIGHT, fill=tk.BOTH, expand=True, padx=5, pady=5)
# 员工列表区域
employee_list_frame = ttk.LabelFrame(view_frame)
employee_list_frame.pack(fill=tk.X, pady=10)
# 利用Treeview控件显示员工列表
tree = ttk.Treeview(employee_list_frame, columns=('Enumber', 'Ename', 'Egender', 'Eage', 'Edepartment', 'Eposition', 'Emobile'), show='headings')
tree.heading('Enumber', text='工号')
tree.heading('Ename', text='姓名')
tree.heading('Egender', text='性别')
tree.heading('Eage', text='年龄')
tree.heading('Edepartment', text='部门')
tree.heading('Eposition', text='职务')
tree.heading('Emobile', text='手机号码')
tree.column('Enumber', width=80, anchor="center")
tree.column('Ename', width=80, anchor="center")
tree.column('Egender', width=60, anchor="center")
tree.column('Eage', width=60, anchor="center")
tree.column('Edepartment', width=80, anchor="center")
tree.column('Eposition', width=80, anchor="center")
tree.column('Emobile', width=120, anchor="center")
tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 刷新员工列表
tree.insert('', 'end', values=(employee_data['Enumber'],
employee_data['Ename'],
employee_data['Egender'],
employee_data['Eage'],
employee_data['Edepartment'],
employee_data['Eposition'],
employee_data['Emobile']))
# 创建滚动条控件
scrollbar = ttk.Scrollbar(employee_list_frame, orient=tk.VERTICAL)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
tree.configure(yscrollcommand=scrollbar.set)
scrollbar.config(command=tree.yview)
# 功能按钮
button_frame = ttk.Frame(view_frame)
button_frame.pack(fill=tk.X, pady=10)
ttk.Button(button_frame, text="查看商品信息", command=self.commodity_widgets).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="查看采购信息", command=lambda:show_info(self.app, "请自行添加代码,更多教程请进入www.pyhint.com学习")).pack(side=tk.LEFT, padx=5)
ttk.Button(button_frame, text="退出系统", command=self.app.destroy).pack(side=tk.LEFT, padx=5)
# 创建商品信息显示页面
def commodity_widgets(self):
# 主框架
self.commodity_window = tk.Toplevel(self.app)
self.commodity_window.title('商品信息')
# 设置窗口居中
window_width = 700
window_height = 630
screen_width = self.commodity_window.winfo_screenwidth()
screen_height = self.commodity_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.commodity_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.commodity_window.resizable(width=False, height=False)
commodity_frame = ttk.Frame(self.commodity_window)
commodity_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 顶部标题框架
top_frame = tk.Frame(commodity_frame, padx=10, pady=5)
top_frame.pack(fill=tk.X, padx=5, pady=5)
top_Label = tk.Label(top_frame, text="商品信息管理", font=("宋体", 20), width=30)
top_Label.pack(fill=tk.X, expand=True)
# 商品信息列表面板
list_frame = ttk.LabelFrame(commodity_frame, text="所有商品信息列表")
list_frame.pack(fill=tk.X, padx=5, pady=5)
# 搜索框架
search_frame = ttk.Frame(list_frame)
search_frame.pack(fill=tk.X, pady=10)
self.search_commodity_entry = ttk.Entry(search_frame)
self.search_commodity_entry.pack(side=tk.LEFT)
ttk.Button(search_frame, text="搜索", command=self.search_commodity).pack(side=tk.LEFT, padx=5)
# 创建“汇总”信息,显示商品信息的数量
self.count = tk.Text(search_frame, relief=tk.FLAT, bg='#f0f0f0', font=10, width=2, height=1)
self.count.pack(side=tk.RIGHT)
total_label = tk.Label(search_frame, text='汇总:', font=10)
total_label.pack(side=tk.RIGHT)
# 利用Treeview控件显示商品列表
self.list_tree = ttk.Treeview(list_frame, columns=('Cnumber', 'Cname', 'Ccategory', 'Cprice', 'Cspecifications', 'Csupplier', 'Cinventory'), show='headings')
self.list_tree.heading('Cnumber', text='商品编号')
self.list_tree.heading('Cname', text='商品名称')
self.list_tree.heading('Ccategory', text='类别')
self.list_tree.heading('Cprice', text='单价')
self.list_tree.heading('Cspecifications', text='商品规格')
self.list_tree.heading('Csupplier', text='供应商')
self.list_tree.heading('Cinventory', text='库存')
self.list_tree.column('Cnumber', width=80, anchor="center")
self.list_tree.column('Cname', width=80, anchor="center")
self.list_tree.column('Ccategory', width=80, anchor="center")
self.list_tree.column('Cprice', width=80, anchor="center")
self.list_tree.column('Cspecifications', width=80, anchor="center")
self.list_tree.column('Csupplier', width=120, anchor="center")
self.list_tree.column('Cinventory', width=80, anchor="center")
self.list_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 创建滚动条控件
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.list_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.list_tree.yview)
# 刷新商品列表
self.refresh_commodity()
# 商品详细信息
detail_frame = ttk.LabelFrame(commodity_frame, text="商品详细信息")
detail_frame.pack(fill=tk.X, pady=5)
self.detail_text = tk.Text(detail_frame, width=20, height=8)
self.detail_text.pack(fill=tk.BOTH, expand=True)
# 关闭窗口框架
help_frame = ttk.Frame(commodity_frame)
help_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=10)
ttk.Button(help_frame, text="关闭商品信息窗口", command=self.commodity_window.destroy).pack(side=tk.LEFT, padx=5)
# 当鼠标或键盘操作选中商品列表中的某一行时,会触发该事件对应的处理函数
self.list_tree.bind('<<TreeviewSelect>>', self.on_commodity_selected)
# 刷新商品列表
def refresh_commodity(self):
# 清空当前列表
for item in self.list_tree.get_children():
self.list_tree.delete(item)
# 添加商品数据
commodity_data = self.manager_control.search_all_commodity()
for commodity in commodity_data:
self.list_tree.insert('', 'end', values=(
commodity['Cnumber'],
commodity['Cname'],
commodity['Ccategory'],
commodity['Cprice'],
commodity['Cspecifications'],
commodity['Csupplier'],
commodity['Cinventory'],
))
# “汇总”统计输出
self.count.delete(1.0, tk.END)
self.count.insert(tk.END, len(self.list_tree.get_children()))
# 搜索商品
def search_commodity(self):
keyword = self.search_commodity_entry.get().strip()
if not keyword:
# 刷新商品列表
self.refresh_commodity()
return
# 清空当前列表
for item in self.list_tree.get_children():
self.list_tree.delete(item)
# 添加搜索结果
commodity_data = self.manager_control.search_commodity(keyword)
for commodity in commodity_data:
self.list_tree.insert('', 'end', values=(
commodity['Cnumber'],
commodity['Cname'],
commodity['Ccategory'],
commodity['Cprice'],
commodity['Cspecifications'],
commodity['Csupplier'],
commodity['Cinventory'],
))
# “汇总”统计输出
self.count.delete(1.0, tk.END)
self.count.insert(tk.END, len(self.list_tree.get_children()))
# 鼠标选择商品时显示该商品详细信息
def on_commodity_selected(self, event):
selected_item = self.list_tree.selection()
if not selected_item:
return
commodity_id = self.list_tree.item(selected_item)['values'][0]
commodity = self.manager_control.search_commodity_id(commodity_id)
if commodity:
information = f"商品编号: {commodity['Cnumber']}\n"
information += f"商品名称: {commodity['Cname']}\n"
information += f"类别: {commodity['Ccategory']}\n"
information += f"单价: {commodity['Cprice']}\n"
information += f"商品规格: {commodity['Cspecifications']}\n"
information += f"供应商: {commodity['Csupplier']}\n"
information += f"库存: {commodity['Cinventory']}"
self.detail_text.delete(1.0, tk.END)
self.detail_text.insert(tk.END, information)
# 显示员工窗口
def run(self):
self.app.mainloop()
# 创建管理员界面,管理员账号可以管理所有信息包括员工信息和商品信息等
class AdminWindow:
def __init__(self, username):
self.username = username
self.manager_control = ControlData()
self.app = tk.Tk()
self.app.title(f"超市进销存管理系统(管理员)-{username}管理员登录")
# 设置窗口居中
window_width = 830
window_height = 520
screen_width = self.app.winfo_screenwidth()
screen_height = self.app.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.app.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.app.resizable(width=False, height=False)
# 窗口样式配置
self.style = ttk.Style()
self.set_styles()
# 主界面创建
self.ManagerPage()
# 将窗口关闭事件与confirm_close函数关联
self.app.protocol("WM_DELETE_WINDOW", self.confirm_close)
# 点击关闭窗口触发函数
def confirm_close(self):
if messagebox.askokcancel("退出", "你确定要退出吗?"): # 弹出确认对话框
self.app.destroy() # 点击确定后关闭窗口
# 定义样式函数
def set_styles(self):
# 设置主题为clam
self.style.theme_use('clam')
# 组件基础样式配置
self.style.configure('TFrame', background='#F3F3F3')
self.style.configure('TLabel', background='#F3F3F3',
foreground='#605E5C')
self.style.configure('TEntry', fieldbackground='#FFFFFF',
bordercolor='#CCCCCC', relief='solid')
self.style.configure('TButton', padding=3, relief='flat',
background='#0078D4',
font=('宋体', 12),
foreground='white')
self.style.map('TButton',
background=[('active', '#004da3'), ('disabled', '#E0E0E0')],
foreground=[('disabled', '#A0A0A0')])
self.style.configure('TLabelframe', bordercolor='#D0D0D0',
relief='groove', padding=10, background='#F3F3F3')
self.style.configure('TLabelframe.Label', padding=10, foreground='#0078D4', font=('宋体', 14, 'bold'), background='#F3F3F3')
def ManagerPage(self):
# 添加商品操作按钮控件,用于修改或显示商品信息
Button1_Add = tk.Button(self.app, text = '员工信息', bg = '#56cdff', font = ('黑体', 15), command = self.employee, width = 20)
Button1_Add.place(x = 40, y = 30, anchor = 'nw')
Button2_Del = tk.Button(self.app, text = '商品信息', bg = '#56cdff', font = ('黑体', 15), command = self.commodity, width = 20)
Button2_Del.place(x = 40, y = 90, anchor = 'nw')
Button3_Mod = tk.Button(self.app, text = '采购信息', bg = '#56cdff', font = ('黑体', 15), command = self.buy, width = 20)
Button3_Mod.place(x = 40, y = 150, anchor = 'nw')
Button4_Ser = tk.Button(self.app, text = '供应商信息', bg = '#56cdff', font = ('黑体', 15), command = self.supplier, width = 20)
Button4_Ser.place(x = 40, y = 210, anchor = 'nw')
Button5_Show = tk.Button(self.app, text = '会员信息', bg = '#56cdff', font = ('黑体', 15), command = self.member, width = 20)
Button5_Show.place(x = 40, y = 270, anchor = 'nw')
Button6_Exit = tk.Button(self.app, text = '关于程序', bg = '#56cdff', font = ('黑体', 15), command = self.index_about, width = 20)
Button6_Exit.place(x = 40, y = 330, anchor = 'nw')
Button6_Exit = tk.Button(self.app, text = '本程序讲解', bg = '#56cdff', font = ('黑体', 15), command = help_window, width = 20)
Button6_Exit.place(x = 40, y = 390, anchor = 'nw')
Button6_Exit = tk.Button(self.app, text = '退出', bg = '#56cdff', font = ('黑体', 15), command = self.index_quit, width = 20)
Button6_Exit.place(x = 40, y = 450, anchor = 'nw')
# 创建一个Text控件,用于输出程序说明信息
txt = '''
>>>欢迎使用超市进销存管理系统<<<
说明:本程序是一个基于Python开发的超市进销存管理系统。
使用了Python的Tkinter库构建GUI图形用户界面,并结合SQLite3库进行数据存储。
运行该程序时,默认会在当前工作目录下创建一个名为“manage.db”的数据库文件,用于存储所有信息。
支持查询、添加、修改、删除信息,并且支持将数据列表导出到Excel文件中。
管理员账号在员工信息页面或商品信息页面,鼠标双击任意一行,即可实现编辑信息的功能,鼠标右键点击任意一行,会显示“删除”按钮。
'''
Show_result = tk.Text(self.app, spacing1=2, spacing2=2, spacing3=2, wrap='word', font=10, width=40, height=10)
Show_result.place(x = "280", y = "30", width = "500", height = "456")
Show_result.insert(tk.END, txt)
def employee(self): # 员工信息
self.admin_employee()
def commodity(self): # 商品信息
self.admin_commodity()
def buy(self): # 采购信息
show_info(self.app, "请自行添加代码,更多教程请进入www.pyhint.com学习")
def supplier(self):# 供应商信息
show_info(self.app, "请自行添加代码,更多教程请进入www.pyhint.com学习")
def member(self): # 会员信息
show_info(self.app, "请自行添加代码,更多教程请进入www.pyhint.com学习")
# 关于本程序
def index_about(self):
program_about()
# 退出-销毁界面
def index_quit(self):
self.app.destroy()
# 创建员工信息管理控件
def admin_employee(self):
self.admin_employee_window = tk.Toplevel(self.app)
self.admin_employee_window.title('员工信息管理')
# 设置窗口居中
window_width = 800
window_height = 660
screen_width = self.admin_employee_window.winfo_screenwidth()
screen_height = self.admin_employee_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.admin_employee_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.admin_employee_window.resizable(width=False, height=False)
# 主框架
main_frame = tk.Frame(self.admin_employee_window)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 顶部标题框架
top_frame = tk.Frame(main_frame, padx=10, pady=5)
top_frame.pack(fill=tk.X, padx=5, pady=5)
top_Label = tk.Label(top_frame, text="员工信息管理", font=("宋体", 20), width=30)
top_Label.pack(fill=tk.X, expand=True)
# 员工信息列表面板
list_frame = ttk.LabelFrame(main_frame, text="所有员工信息列表")
list_frame.pack(fill=tk.X, padx=5, pady=5)
# 搜索框架
search_frame = ttk.Frame(list_frame)
search_frame.pack(fill=tk.X, pady=10)
self.search_employee_entry = ttk.Entry(search_frame)
self.search_employee_entry.pack(side=tk.LEFT)
ttk.Button(search_frame, text="搜索", command=self.search_employee).pack(side=tk.LEFT, padx=5)
# 创建“汇总”信息,显示员工信息的数量
self.employee_count = tk.Text(search_frame, relief=tk.FLAT, bg='#f0f0f0', font=10, width=2, height=1)
self.employee_count.pack(side=tk.RIGHT)
total_label = tk.Label(search_frame, text='汇总:', font=10)
total_label.pack(side=tk.RIGHT)
# 利用Treeview控件显示员工列表
self.employee_tree = ttk.Treeview(list_frame, columns=('Enumber', 'Ename', 'Egender', 'Eage', 'Edepartment', 'Eposition', 'Emobile'), show='headings')
self.employee_tree.heading('Enumber', text='工号')
self.employee_tree.heading('Ename', text='姓名')
self.employee_tree.heading('Egender', text='性别')
self.employee_tree.heading('Eage', text='年龄')
self.employee_tree.heading('Edepartment', text='部门')
self.employee_tree.heading('Eposition', text='职务')
self.employee_tree.heading('Emobile', text='手机号码')
self.employee_tree.column('Enumber', width=80, anchor="center")
self.employee_tree.column('Ename', width=80, anchor="center")
self.employee_tree.column('Egender', width=60, anchor="center")
self.employee_tree.column('Eage', width=60, anchor="center")
self.employee_tree.column('Edepartment', width=80, anchor="center")
self.employee_tree.column('Eposition', width=80, anchor="center")
self.employee_tree.column('Emobile', width=120, anchor="center")
self.employee_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 刷新员工列表
self.refresh_employee()
# 创建滚动条控件
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.employee_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.employee_tree.yview)
# 当鼠标或键盘操作选中员工列表中的某一行时,会触发该事件对应的处理函数
self.employee_tree.bind('<<TreeviewSelect>>', self.on_employee_selected)
# 鼠标双击员工信息列表任意一行,可以触发修改员工信息页面
def on_double_click(event):
# 获取被双击的项的IID
iid = self.employee_tree.focus()
if iid == '':
return # 如果没有选中任何一行,则直接返回
# 选中指定的行
self.employee_tree.selection_set((iid,))
self.edit_employee()
# 绑定鼠标双击事件
self.employee_tree.bind("<Double-1>", on_double_click)
# 鼠标右键点击员工信息列表任意一行,就会显示“删除该员工”按钮
def on_right_click(event):
# 获取当前焦点项的iid
iid = self.employee_tree.focus()
# 选中指定的行
self.employee_tree.selection_set((iid,))
if iid:
# 弹出菜单选项
menu = tk.Menu(self.employee_tree, tearoff=0)
menu.add_command(label="删除该员工", command=self.delete_employee)
menu.tk_popup(event.x_root, event.y_root)
# 绑定鼠标右键点击事件
self.employee_tree.bind("<Button-3>", on_right_click)
# 员工操作按钮
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=5)
ttk.Button(button_frame, text="显示所有员工信息", command=self.refresh_employee).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="添加员工", command=self.add_employee).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="修改员工", command=self.edit_employee).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="删除员工", command=self.delete_employee).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="导出以上员工信息", command=self.export_employee).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="关闭窗口", command=self.admin_employee_window.destroy).pack(side=tk.LEFT, padx=6)
# 员工信息面板
information_frame = ttk.Frame(main_frame)
information_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=5)
# 员工详细信息
detail_frame = ttk.LabelFrame(information_frame, text="员工详细信息")
detail_frame.pack(fill=tk.X, pady=5)
self.detail_text = tk.Text(detail_frame, width=20, height=8)
self.detail_text.pack(fill=tk.BOTH, expand=True)
# 关于程序讲解
help_frame = ttk.Frame(information_frame)
help_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=5)
ttk.Button(help_frame, text="关于本程序", command=program_about).pack(side=tk.LEFT, padx=6)
ttk.Button(help_frame, text="本程序讲解", command=help_window).pack(side=tk.LEFT, padx=6)
self.admin_employee_window.mainloop()
# 刷新员工列表
def refresh_employee(self):
# 清空当前列表
for item in self.employee_tree.get_children():
self.employee_tree.delete(item)
# 添加员工数据
employee_data = self.manager_control.search_all_employee()
for employee in employee_data:
self.employee_tree.insert('', 'end', values=(
employee['Enumber'],
employee['Ename'],
employee['Egender'],
employee['Eage'],
employee['Edepartment'],
employee['Eposition'],
employee['Emobile'],
))
# “汇总”统计输出
self.employee_count.delete(1.0, tk.END)
self.employee_count.insert(tk.END, len(self.employee_tree.get_children()))
# 搜索员工
def search_employee(self):
keyword = self.search_employee_entry.get().strip()
if not keyword:
# 刷新员工列表
self.refresh_employee()
return
# 清空当前列表
for item in self.employee_tree.get_children():
self.employee_tree.delete(item)
# 添加搜索结果
employee_data = self.manager_control.search_employee(keyword)
for employee in employee_data:
self.employee_tree.insert('', 'end', values=(
employee['Enumber'],
employee['Ename'],
employee['Egender'],
employee['Eage'],
employee['Edepartment'],
employee['Eposition'],
employee['Emobile'],
))
# “汇总”统计输出
self.employee_count.delete(1.0, tk.END)
self.employee_count.insert(tk.END, len(self.employee_tree.get_children()))
# 鼠标选择员工时显示该员工详细信息
def on_employee_selected(self, event):
selected_item = self.employee_tree.selection()
if not selected_item:
return
employee_id = self.employee_tree.item(selected_item)['values'][0]
employee = self.manager_control.search_employee_id(employee_id)
if employee:
information = f"工号: {employee['Enumber']}\n"
information += f"姓名: {employee['Ename']}\n"
information += f"性别: {employee['Egender']}\n"
information += f"年龄: {employee['Eage']}\n"
information += f"部门: {employee['Edepartment']}\n"
information += f"职务: {employee['Eposition']}\n"
information += f"手机号码: {employee['Emobile']}"
self.detail_text.delete(1.0, tk.END)
self.detail_text.insert(tk.END, information)
# 添加员工方法
def add_employee(self):
add_window = tk.Toplevel(self.admin_employee_window)
add_window.title("添加员工")
# 设置窗口居中
window_width = 500
window_height = 520
screen_width = add_window.winfo_screenwidth()
screen_height = add_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
add_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
add_window.resizable(width=False, height=False)
# 创建标题标签控件
Show_result = tk.Label(add_window, text=">>>添加员工信息<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
Show_result.place(x = 50, y = 30, width = 400, height = 50)
# 工号
tk.Label(add_window, text="工号(不可重复):", font = ('宋体', 12), width = 15).place(x = 75, y = 100, anchor = 'nw')
id_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
id_entry.place(x = 210, y = 100, anchor = 'nw')
# 姓名
tk.Label(add_window, text="姓名:", font = ('宋体', 12), width = 15).place(x = 75, y = 150, anchor = 'nw')
name_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
name_entry.place(x = 210, y = 150, anchor = 'nw')
# 性别
tk.Label(add_window, text="性别:", font = ('宋体', 12), width = 15).place(x = 75, y = 200, anchor = 'nw')
Egender_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Egender_entry.place(x = 210, y = 200, anchor = 'nw')
# 年龄
tk.Label(add_window, text="年龄:", font = ('宋体', 12), width = 15).place(x = 75, y = 250, anchor = 'nw')
Eage_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Eage_entry.place(x = 210, y = 250, anchor = 'nw')
# 部门
tk.Label(add_window, text="部门:", font = ('宋体', 12), width = 15).place(x = 75, y = 300, anchor = 'nw')
Edepartment_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Edepartment_entry.place(x = 210, y = 300, anchor = 'nw')
# 职务
tk.Label(add_window, text="职务:", font = ('宋体', 12), width = 15).place(x = 75, y = 350, anchor = 'nw')
Eposition_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Eposition_entry.place(x = 210, y = 350, anchor = 'nw')
# 手机号码
tk.Label(add_window, text="手机号码:", font = ('宋体', 12), width = 15).place(x = 75, y = 400, anchor = 'nw')
Emobile_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Emobile_entry.place(x = 210, y = 400, anchor = 'nw')
# 保存员工信息
def save_employee():
employee_data = {
'Enumber': id_entry.get(),
'Ename': name_entry.get(),
'Egender': Egender_entry.get(),
'Eage': Eage_entry.get(),
'Edepartment': Edepartment_entry.get(),
'Eposition': Eposition_entry.get(),
'Emobile': Emobile_entry.get()
}
# 从字典中获取所有的值到列表中
employee_list = list(employee_data.values())
# 检查每个输入框是否为空
for result in employee_list:
if not result:
show_error(self.app, "输入的内容不能为空!")
return
id = str(id_entry.get())
data = search_employee_id(id)
if not data:
self.manager_control.add_employee(employee_data)
show_sucess(self.app, "添加成功!")
add_window.destroy()
# 刷新员工列表
self.refresh_employee()
else:
show_error(self.app, "工号已存在!")
# 定义“保存”按钮
save_button = ttk.Button(add_window, text="保存", command=save_employee, width=15)
save_button.place(x = 105, y = 450, anchor = 'nw')
# 定义“取消”按钮
cancel_button = ttk.Button(add_window, text="取消", command=add_window.destroy, width=15)
cancel_button.place(x = 280, y = 450, anchor = 'nw')
# 修改员工信息
def edit_employee(self):
selected_item = self.employee_tree.selection()
if not selected_item:
show_error(self.app, "请先选择一个员工!")
return
employee_id = self.employee_tree.item(selected_item)['values'][0]
employee = self.manager_control.search_employee_id(employee_id)
if not employee:
show_error(self.app, "找不到该员工!")
return
modify_window = tk.Toplevel(self.admin_employee_window)
modify_window.title("修改员工信息")
# 设置窗口居中
window_width = 500
window_height = 520
screen_width = modify_window.winfo_screenwidth()
screen_height = modify_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
modify_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
modify_window.resizable(width=False, height=False)
# 创建标题标签控件
Show_result = tk.Label(modify_window, text=">>>修改员工信息<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
Show_result.place(x = 50, y = 30, width = 400, height = 50)
# 工号(不可编辑)
tk.Label(modify_window, text="工号(不可修改):", font = ('宋体', 12), width = 15).place(x = 75, y = 100, anchor = 'nw')
Employ_ID = tk.StringVar()
Employ_ID.set(employee['Enumber'])
number_entry = tk.Entry(modify_window, show = None, font = ('宋体', 15), textvariable = Employ_ID, width = 20)
number_entry.place(x = 210, y = 100, anchor = 'nw')
# 设置默认值为相应的工号,工号不可改变
def on_key_release(event):
if event.widget.get():
event.widget.delete(0, tk.END)
event.widget.insert(0, employee['Enumber'])
# 使用bind绑定函数,当用户释放任意按键时,绑定的回调函数会被触发。
number_entry.bind('<KeyRelease>', on_key_release)
# 姓名
tk.Label(modify_window, text="姓名:", font = ('宋体', 12), width = 15).place(x = 75, y = 150, anchor = 'nw')
name_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
name_entry.insert(0, employee['Ename'])
name_entry.place(x = 210, y = 150, anchor = 'nw')
# 性别
tk.Label(modify_window, text="性别:", font = ('宋体', 12), width = 15).place(x = 75, y = 200, anchor = 'nw')
Egender_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Egender_entry.insert(0, employee['Egender'])
Egender_entry.place(x = 210, y = 200, anchor = 'nw')
# 年龄
tk.Label(modify_window, text="年龄:", font = ('宋体', 12), width = 15).place(x = 75, y = 250, anchor = 'nw')
Eage_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Eage_entry.insert(0, employee['Eage'])
Eage_entry.place(x = 210, y = 250, anchor = 'nw')
# 部门
tk.Label(modify_window, text="部门:", font = ('宋体', 12), width = 15).place(x = 75, y = 300, anchor = 'nw')
Edepartment_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Edepartment_entry.insert(0, employee['Edepartment'])
Edepartment_entry.place(x = 210, y = 300, anchor = 'nw')
# 职务
tk.Label(modify_window, text="职务:", font = ('宋体', 12), width = 15).place(x = 75, y = 350, anchor = 'nw')
Eposition_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Eposition_entry.insert(0, employee['Eposition'])
Eposition_entry.place(x = 210, y = 350, anchor = 'nw')
# 手机号码
tk.Label(modify_window, text="手机号码:", font = ('宋体', 12), width = 15).place(x = 75, y = 400, anchor = 'nw')
Emobile_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Emobile_entry.insert(0, employee['Emobile'])
Emobile_entry.place(x = 210, y = 400, anchor = 'nw')
# 更新员工信息
def update_employee():
new_data = {
'Ename': name_entry.get(),
'Egender':Egender_entry.get(),
'Eage':Eage_entry.get(),
'Edepartment':Edepartment_entry.get(),
'Eposition':Eposition_entry.get(),
'Emobile':Emobile_entry.get()
}
# 从字典中获取所有的值到列表中
employee_list = list(new_data.values())
# 检查每个输入框是否为空
for result in employee_list:
if not result:
show_error(self.app, "输入的内容不能为空!")
return
if self.manager_control.update_employee(employee['Enumber'], new_data):
show_sucess(self.app, "员工信息更新成功!")
modify_window.destroy()
# 刷新员工列表
self.refresh_employee()
self.on_employee_selected(None)
else:
show_error(self.app, "更新失败!")
# 保存按钮
save_button = ttk.Button(modify_window, text="保存", command=update_employee, width=15)
save_button.place(x = 105, y = 450, anchor = 'nw')
# 取消按钮
cancel_button = ttk.Button(modify_window, text="取消", command=modify_window.destroy, width=15)
cancel_button.place(x = 280, y = 450, anchor = 'nw')
# 删除员工
def delete_employee(self):
selected_item = self.employee_tree.selection()
if not selected_item:
show_error(self.app, "请先选择一个员工!")
return
employee_id = self.employee_tree.item(selected_item)['values'][0]
employee_name = self.employee_tree.item(selected_item)['values'][1]
add = tk.Toplevel(self.app)
add.title("确认")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 240
height = 150
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text="确定要删除该员工吗?", font=('黑体', 14)).place(x=20, y=15)
tk.Label(add, text=f"“{employee_name}”", font=('黑体', 14)).place(x=70, y=50)
def confirmm():
if self.manager_control.delete_employee(employee_id):
show_sucess(self.app,"员工删除成功!")
# 刷新员工列表
self.refresh_employee()
self.detail_text.delete(1.0, tk.END)
add.destroy()
else:
show_error(self.app, "删除失败!")
def cancel():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).place(x=20, y=100)
# 取消按钮
tk.Button(add, text='取消', font=('黑体', 12), width=10, command=cancel).place(x=130, y=100)
# 获取当前项的所有列值组成的元组
def all_employee_rows(self):
rows = []
for item in self.employee_tree.get_children():
row = self.employee_tree.item(item, 'values')
rows.append(row)
return rows
# 导出员工信息到指定Excel表格
def export_employee(self):
export_result = self.all_employee_rows()
if not any(len(employee_list[0]) > 0 for employee_list in export_result):
show_error(self.app, "没有数据可导出")
return
try:
# 自定义列名
columns = ['工号', '姓名', '性别', '年龄', '部门', '职务', '手机号码']
# 将数据转换为DataFrame
df = pandas.DataFrame(export_result, columns=columns)
save_path = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel文件", "*.xlsx")])
if save_path:
df.to_excel(save_path, index=False)
show_sucess(self.app, "导出成功!")
except PermissionError:
show_error(self.app, "Excel文件被占用,请关闭文件后重试")
except Exception as e:
show_error(self.app, f"导出失败:{str(e)}")
# 创建商品信息管理控件
def admin_commodity(self):
self.admin_commodity_window = tk.Toplevel(self.app)
self.admin_commodity_window.title('商品信息管理')
# 设置窗口居中
window_width = 800
window_height = 660
screen_width = self.admin_commodity_window.winfo_screenwidth()
screen_height = self.admin_commodity_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
self.admin_commodity_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
self.admin_commodity_window.resizable(width=False, height=False)
# 主框架
main_frame = tk.Frame(self.admin_commodity_window)
main_frame.pack(fill=tk.BOTH, expand=True, padx=10, pady=10)
# 顶部标题框架
top_frame = tk.Frame(main_frame, padx=10, pady=5)
top_frame.pack(fill=tk.X, padx=5, pady=5)
top_Label = tk.Label(top_frame, text="商品信息管理", font=("宋体", 20), width=30)
top_Label.pack(fill=tk.X, expand=True)
# 商品信息列表面板
list_frame = ttk.LabelFrame(main_frame, text="所有商品信息列表")
list_frame.pack(fill=tk.X, padx=5, pady=5)
# 搜索框架
search_frame = ttk.Frame(list_frame)
search_frame.pack(fill=tk.X, pady=10)
self.search_commodity_entry = ttk.Entry(search_frame)
self.search_commodity_entry.pack(side=tk.LEFT)
ttk.Button(search_frame, text="搜索", command=self.search_commodity).pack(side=tk.LEFT, padx=5)
# 创建“汇总”信息,显示商品信息的数量
self.commodity_count = tk.Text(search_frame, relief=tk.FLAT, bg='#f0f0f0', font=10, width=2, height=1)
self.commodity_count.pack(side=tk.RIGHT)
total_label = tk.Label(search_frame, text='汇总:', font=10)
total_label.pack(side=tk.RIGHT)
# 利用Treeview控件显示商品列表
self.commodity_tree = ttk.Treeview(list_frame, columns=('Cnumber', 'Cname', 'Ccategory', 'Cprice', 'Cspecifications', 'Csupplier', 'Cinventory'), show='headings')
self.commodity_tree.heading('Cnumber', text='商品编号')
self.commodity_tree.heading('Cname', text='商品名称')
self.commodity_tree.heading('Ccategory', text='类别')
self.commodity_tree.heading('Cprice', text='单价')
self.commodity_tree.heading('Cspecifications', text='商品规格')
self.commodity_tree.heading('Csupplier', text='供应商')
self.commodity_tree.heading('Cinventory', text='库存')
self.commodity_tree.column('Cnumber', width=80, anchor="center")
self.commodity_tree.column('Cname', width=80, anchor="center")
self.commodity_tree.column('Ccategory', width=80, anchor="center")
self.commodity_tree.column('Cprice', width=80, anchor="center")
self.commodity_tree.column('Cspecifications', width=80, anchor="center")
self.commodity_tree.column('Csupplier', width=120, anchor="center")
self.commodity_tree.column('Cinventory', width=80, anchor="center")
self.commodity_tree.pack(side=tk.LEFT, fill=tk.BOTH, expand=True)
# 刷新商品列表
self.refresh_commodity()
# 创建滚动条控件
scrollbar = ttk.Scrollbar(list_frame, orient=tk.VERTICAL)
scrollbar.pack(side=tk.RIGHT, fill=tk.Y)
self.commodity_tree.configure(yscrollcommand=scrollbar.set)
scrollbar.config(command=self.commodity_tree.yview)
# 当鼠标或键盘操作选中商品列表中的某一行时,会触发该事件对应的处理函数
self.commodity_tree.bind('<<TreeviewSelect>>', self.on_commodity_selected)
# 鼠标双击商品信息列表任意一行,可以触发修改商品信息页面
def on_double_click(event):
# 获取被双击的项的IID
iid = self.commodity_tree.focus()
if iid == '':
return # 如果没有选中任何一行,则直接返回
# 选中指定的行
self.commodity_tree.selection_set((iid,))
self.edit_commodity()
# 绑定鼠标双击事件
self.commodity_tree.bind("<Double-1>", on_double_click)
# 鼠标右键点击商品信息列表任意一行,就会显示“删除该商品”按钮
def on_right_click(event):
# 获取当前焦点项的iid
iid = self.commodity_tree.focus()
# 选中指定的行
self.commodity_tree.selection_set((iid,))
if iid:
# 弹出菜单选项
menu = tk.Menu(self.commodity_tree, tearoff=0)
menu.add_command(label="删除该商品", command=self.delete_commodity)
menu.tk_popup(event.x_root, event.y_root)
# 绑定鼠标右键点击事件
self.commodity_tree.bind("<Button-3>", on_right_click)
# 商品操作按钮
button_frame = ttk.Frame(main_frame)
button_frame.pack(fill=tk.X, pady=5)
ttk.Button(button_frame, text="显示所有商品信息", command=self.refresh_commodity).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="添加商品", command=self.add_commodity).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="修改商品", command=self.edit_commodity).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="删除商品", command=self.delete_commodity).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="导出以上商品信息", command=self.export_commodity).pack(side=tk.LEFT, padx=6)
ttk.Button(button_frame, text="关闭窗口", command=self.admin_commodity_window.destroy).pack(side=tk.LEFT, padx=6)
# 左侧信息面板
information_frame = ttk.Frame(main_frame)
information_frame.pack(side=tk.LEFT, fill=tk.BOTH, expand=True, padx=10, pady=5)
# 商品详细信息
detail_frame = ttk.LabelFrame(information_frame, text="商品详细信息")
detail_frame.pack(fill=tk.X, pady=5)
self.detail_text = tk.Text(detail_frame, width=20, height=8)
self.detail_text.pack(fill=tk.BOTH, expand=True)
# 关于程序讲解
help_frame = ttk.Frame(information_frame)
help_frame.pack(side=tk.BOTTOM, fill=tk.X, pady=5)
ttk.Button(help_frame, text="关于本程序", command=program_about).pack(side=tk.LEFT, padx=6)
ttk.Button(help_frame, text="本程序讲解", command=help_window).pack(side=tk.LEFT, padx=6)
self.admin_commodity_window.mainloop()
# 刷新商品列表
def refresh_commodity(self):
# 清空当前列表
for item in self.commodity_tree.get_children():
self.commodity_tree.delete(item)
# 添加商品数据
commodity_data = self.manager_control.search_all_commodity()
for commodity in commodity_data:
self.commodity_tree.insert('', 'end', values=(
commodity['Cnumber'],
commodity['Cname'],
commodity['Ccategory'],
commodity['Cprice'],
commodity['Cspecifications'],
commodity['Csupplier'],
commodity['Cinventory'],
))
# “汇总”统计输出
self.commodity_count.delete(1.0, tk.END)
self.commodity_count.insert(tk.END, len(self.commodity_tree.get_children()))
# 搜索商品
def search_commodity(self):
keyword = self.search_commodity_entry.get().strip()
if not keyword:
# 刷新商品列表
self.refresh_commodity()
return
# 清空当前列表
for item in self.commodity_tree.get_children():
self.commodity_tree.delete(item)
# 添加搜索结果
commodity_data = self.manager_control.search_commodity(keyword)
for commodity in commodity_data:
self.commodity_tree.insert('', 'end', values=(
commodity['Cnumber'],
commodity['Cname'],
commodity['Ccategory'],
commodity['Cprice'],
commodity['Cspecifications'],
commodity['Csupplier'],
commodity['Cinventory'],
))
# “汇总”统计输出
self.commodity_count.delete(1.0, tk.END)
self.commodity_count.insert(tk.END, len(self.commodity_tree.get_children()))
# 鼠标选择商品时显示该商品详细信息
def on_commodity_selected(self, event):
selected_item = self.commodity_tree.selection()
if not selected_item:
return
commodity_id = self.commodity_tree.item(selected_item)['values'][0]
commodity = self.manager_control.search_commodity_id(commodity_id)
if commodity:
information = f"商品编号: {commodity['Cnumber']}\n"
information += f"商品名称: {commodity['Cname']}\n"
information += f"类别: {commodity['Ccategory']}\n"
information += f"单价: {commodity['Cprice']}\n"
information += f"商品规格: {commodity['Cspecifications']}\n"
information += f"供应商: {commodity['Csupplier']}\n"
information += f"库存: {commodity['Cinventory']}"
self.detail_text.delete(1.0, tk.END)
self.detail_text.insert(tk.END, information)
# 添加商品方法
def add_commodity(self):
add_window = tk.Toplevel(self.admin_commodity_window)
add_window.title("添加商品")
# 设置窗口居中
window_width = 550
window_height = 530
screen_width = add_window.winfo_screenwidth()
screen_height = add_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
add_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
add_window.resizable(width=False, height=False)
# 创建标题标签控件
Show_result = tk.Label(add_window, text=">>>添加商品信息<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
Show_result.place(x = 70, y = 30, width = 400, height = 50)
# 商品编号
tk.Label(add_window, text="商品编号(不可重复):", font = ('宋体', 12), width = 25).place(x = 55, y = 110, anchor = 'nw')
id_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
id_entry.place(x = 250, y = 110, anchor = 'nw')
# 商品名称
tk.Label(add_window, text="商品名称:", font = ('宋体', 12), width = 25).place(x = 55, y = 160, anchor = 'nw')
name_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
name_entry.place(x = 250, y = 160, anchor = 'nw')
# 类别
tk.Label(add_window, text="类别:", font = ('宋体', 12), width = 25).place(x = 55, y = 210, anchor = 'nw')
Ccategory_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Ccategory_entry.place(x = 250, y = 210, anchor = 'nw')
# 单价
tk.Label(add_window, text="单价:", font = ('宋体', 12), width = 25).place(x = 55, y = 260, anchor = 'nw')
Cprice_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Cprice_entry.place(x = 250, y = 260, anchor = 'nw')
# 商品规格
tk.Label(add_window, text="商品规格:", font = ('宋体', 12), width = 25).place(x = 55, y = 310, anchor = 'nw')
Cspecifications_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Cspecifications_entry.place(x = 250, y = 310, anchor = 'nw')
# 供应商
tk.Label(add_window, text="供应商:", font = ('宋体', 12), width = 25).place(x = 55, y = 360, anchor = 'nw')
Csupplier_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Csupplier_entry.place(x = 250, y = 360, anchor = 'nw')
# 库存
tk.Label(add_window, text="库存:", font = ('宋体', 12), width = 25).place(x = 55, y = 410, anchor = 'nw')
Cinventory_entry = tk.Entry(add_window, font = ('宋体', 15), width = 20)
Cinventory_entry.place(x = 250, y = 410, anchor = 'nw')
# 保存商品信息
def save_commodity():
commodity_data = {
'Cnumber': id_entry.get(),
'Cname': name_entry.get(),
'Ccategory': Ccategory_entry.get(),
'Cprice': Cprice_entry.get(),
'Cspecifications': Cspecifications_entry.get(),
'Csupplier': Csupplier_entry.get(),
'Cinventory': Cinventory_entry.get()
}
# 从字典中获取所有的值到列表中
commodity_list = list(commodity_data.values())
# 检查每个输入框是否为空
for result in commodity_list:
if not result:
show_error(self.app, "输入的内容不能为空!")
return
id = str(id_entry.get())
data = search_commodity_id(id)
if not data:
self.manager_control.add_commodity(commodity_data)
show_sucess(self.app, "添加成功!")
add_window.destroy()
# 刷新商品列表
self.refresh_commodity()
else:
show_error(self.app, "商品编号已存在!")
# 定义“保存”按钮
save_button = ttk.Button(add_window, text="保存", command=save_commodity, width=15)
save_button.place(x = 105, y = 460, anchor = 'nw')
# 定义“取消”按钮
cancel_button = ttk.Button(add_window, text="取消", command=add_window.destroy, width=15)
cancel_button.place(x = 280, y = 460, anchor = 'nw')
# 修改商品信息
def edit_commodity(self):
selected_item = self.commodity_tree.selection()
if not selected_item:
show_error(self.app, "请先选择一个商品!")
return
commodity_id = self.commodity_tree.item(selected_item)['values'][0]
commodity = self.manager_control.search_commodity_id(commodity_id)
if not commodity:
show_error(self.app, "找不到该商品!")
return
modify_window = tk.Toplevel(self.admin_commodity_window)
modify_window.title("修改商品信息")
# 设置窗口居中
window_width = 550
window_height = 530
screen_width = modify_window.winfo_screenwidth()
screen_height = modify_window.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
modify_window.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
modify_window.resizable(width=False, height=False)
# 创建标题标签控件
Show_result = tk.Label(modify_window, text=">>>修改商品信息<<<", bg = "white", fg = "black", font = ("宋体", 18), bd = '0', anchor = 'center')
Show_result.place(x = 70, y = 30, width = 400, height = 50)
# 商品(不可编辑)
tk.Label(modify_window, text="商品编号(不可修改):", font = ('宋体', 12), width = 25).place(x = 55, y = 100, anchor = 'nw')
Employ_ID = tk.StringVar()
Employ_ID.set(commodity['Cnumber'])
number_entry = tk.Entry(modify_window, show = None, font = ('宋体', 15), textvariable = Employ_ID, width = 20)
number_entry.place(x = 250, y = 100, anchor = 'nw')
# 设置默认值为相应的商品,商品不可改变
def on_key_release(event):
if event.widget.get():
event.widget.delete(0, tk.END)
event.widget.insert(0, commodity['Cnumber'])
# 使用bind绑定函数,当用户释放任意按键时,绑定的回调函数会被触发。
number_entry.bind('<KeyRelease>', on_key_release)
# 商品名称
tk.Label(modify_window, text="商品名称:", font = ('宋体', 12), width = 25).place(x = 55, y = 160, anchor = 'nw')
name_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
name_entry.insert(0, commodity['Cname'])
name_entry.place(x = 250, y = 160, anchor = 'nw')
# 类别
tk.Label(modify_window, text="类别:", font = ('宋体', 12), width = 25).place(x = 55, y = 210, anchor = 'nw')
Ccategory_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Ccategory_entry.insert(0, commodity['Ccategory'])
Ccategory_entry.place(x = 250, y = 210, anchor = 'nw')
# 单价
tk.Label(modify_window, text="单价:", font = ('宋体', 12), width = 25).place(x = 55, y = 260, anchor = 'nw')
Cprice_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Cprice_entry.insert(0, commodity['Cprice'])
Cprice_entry.place(x = 250, y = 260, anchor = 'nw')
# 商品规格
tk.Label(modify_window, text="商品规格:", font = ('宋体', 12), width = 25).place(x = 55, y = 310, anchor = 'nw')
Cspecifications_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Cspecifications_entry.insert(0, commodity['Cspecifications'])
Cspecifications_entry.place(x = 250, y = 310, anchor = 'nw')
# 供应商
tk.Label(modify_window, text="供应商:", font = ('宋体', 12), width = 25).place(x = 55, y = 360, anchor = 'nw')
Csupplier_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Csupplier_entry.insert(0, commodity['Csupplier'])
Csupplier_entry.place(x = 250, y = 360, anchor = 'nw')
# 库存
tk.Label(modify_window, text="库存:", font = ('宋体', 12), width = 25).place(x = 55, y = 410, anchor = 'nw')
Cinventory_entry = tk.Entry(modify_window, font = ('宋体', 15), width = 20)
Cinventory_entry.insert(0, commodity['Cinventory'])
Cinventory_entry.place(x = 250, y = 410, anchor = 'nw')
# 更新商品信息
def update_commodity():
new_data = {
'Cname': name_entry.get(),
'Ccategory':Ccategory_entry.get(),
'Cprice':Cprice_entry.get(),
'Cspecifications':Cspecifications_entry.get(),
'Csupplier':Csupplier_entry.get(),
'Cinventory':Cinventory_entry.get()
}
# 从字典中获取所有的值到列表中
commodity_list = list(new_data.values())
# 检查每个输入框是否为空
for result in commodity_list:
if not result:
show_error(self.app, "输入的内容不能为空!")
return
if self.manager_control.update_commodity(commodity['Cnumber'], new_data):
show_sucess(self.app, "商品信息更新成功!")
modify_window.destroy()
# 刷新商品列表
self.refresh_commodity()
self.on_commodity_selected(None)
else:
show_error(self.app, "更新失败!")
# 保存按钮
save_button = ttk.Button(modify_window, text="保存", command=update_commodity, width=15)
save_button.place(x = 105, y = 460, anchor = 'nw')
# 取消按钮
cancel_button = ttk.Button(modify_window, text="取消", command=modify_window.destroy, width=15)
cancel_button.place(x = 280, y = 460, anchor = 'nw')
# 删除商品
def delete_commodity(self):
selected_item = self.commodity_tree.selection()
if not selected_item:
show_error(self.app, "请先选择一个商品!")
return
commodity_id = self.commodity_tree.item(selected_item)['values'][0]
commodity_name = self.commodity_tree.item(selected_item)['values'][1]
add = tk.Toplevel(self.app)
add.title("确认")
screen_width, screen_height = add.maxsize()
# 窗口的宽和高
width = 240
height = 150
centre = '%dx%d+%d+%d' % (width, height, (screen_width - width) / 2,
(screen_height - height) / 2)
add.geometry(centre)
tk.Label(add, text="确定要删除该商品吗?", font=('黑体', 14)).place(x=20, y=15)
tk.Label(add, text=f"“{commodity_name}”", font=('黑体', 14)).place(x=70, y=50)
def confirmm():
if self.manager_control.delete_commodity(commodity_id):
show_sucess(self.app,"商品删除成功!")
# 刷新商品列表
self.refresh_commodity()
self.detail_text.delete(1.0, tk.END)
add.destroy()
else:
show_error(self.app, "删除失败!")
def cancel():
add.destroy()
# 确定按钮
tk.Button(add, text='确定', font=('黑体', 12), width=10, command=confirmm).place(x=20, y=100)
# 取消按钮
tk.Button(add, text='取消', font=('黑体', 12), width=10, command=cancel).place(x=130, y=100)
# 获取当前项的所有列值组成的元组
def all_commodity_rows(self):
rows = []
for item in self.commodity_tree.get_children():
row = self.commodity_tree.item(item, 'values')
rows.append(row)
return rows
# 导出商品信息到指定Excel表格
def export_commodity(self):
export_result = self.all_commodity_rows()
if not any(len(commodity_list[0]) > 0 for commodity_list in export_result):
show_error(self.app, "没有数据可导出")
return
try:
# 自定义列名
columns = ['商品编号', '商品名称', '类别', '单价', '商品规格', '供应商', '库存']
# 将数据转换为DataFrame
df = pandas.DataFrame(export_result, columns=columns)
save_path = filedialog.asksaveasfilename(
defaultextension=".xlsx",
filetypes=[("Excel文件", "*.xlsx")])
if save_path:
df.to_excel(save_path, index=False)
show_sucess(self.app, "导出成功!")
except PermissionError:
show_error(self.app, "Excel文件被占用,请关闭文件后重试")
except Exception as e:
show_error(self.app, f"导出失败:{str(e)}")
# 显示管理员窗口
def run(self):
self.app.mainloop()
# 关于程序页面
def program_about():
about = tk.Tk()
about.title('关于程序')
# 设置窗口居中
window_width = 450
window_height = 520
screen_width = about.winfo_screenwidth()
screen_height = about.winfo_screenheight()
x = (screen_width - window_width) / 2
y = (screen_height - window_height) / 2
about.geometry('%dx%d+%d+%d' % (window_width, window_height, x, y))
about.resizable(width=False, height=False)
about_frame = tk.Frame(about, width=490, height=520)
about_frame.pack()
tk.Label(about_frame, text='超市进销存管理系统', font=("宋体", 16)).place(x=150, y=20)
tk.Label(about_frame, text='使用编程语言:Python', font=("宋体", 14)).place(x=50, y=70)
tk.Label(about_frame, text='使用数据库:SQLite3数据库', font=("宋体", 14)).place(x=50, y=120)
tk.Label(about_frame, text='数据库文件:manage.db', font=("宋体", 14)).place(x=50, y=170)
tk.Label(about_frame, text='修改信息:在信息列表直接双击鼠标', font=("宋体", 14)).place(x=50, y=220)
tk.Label(about_frame, text='删除信息:在信息列表右击鼠标', font=("宋体", 14)).place(x=50, y=270)
tk.Label(about_frame, text='导出信息方式:导出到Excel文件内', font=("宋体", 14)).place(x=50, y=320)
tk.Label(about_frame, text='管理员登录方式:请用管理员账号登录', font=("宋体", 14)).place(x=50, y=370)
tk.Label(about_frame, text='员工登录方式:请用员工账号登录', font=("宋体", 14)).place(x=50, y=420)
tk.Label(about_frame, text='创作者:www.pyhint.com', font=("宋体", 14)).place(x=50, y=470)
about.mainloop()
# 程序讲解页面
def help_window():
webbrowser.open("https://www.pyhint.com/article/158.html")
# 登录成功后,判断账号如果是员工账号则进入员工界面,如果是管理员账号则进入管理员界面
def success_login(username, category):
if category == 'employee':
employee_enter = EmployWindow(username)
employee_enter.run()
elif category == 'admin':
admin_enter = AdminWindow(username)
admin_enter.run()
# 当前模块直接被执行
if __name__ == "__main__":
# 创建登录窗口
login_window = UserLogin(success_login)
login_window.run()