实验设备管理系统的目的主要是为了解决实验室设备管理的需求。假设如果实验室使用了这个系统,可以更方便地进行设备信息的录入、查询、统计和报修等操作,大大提高了设备管理的效率和准确性。
写这篇文章目的性是为了给写程序的学生做参考,提供思路,希望学生能够从这篇文章学到自己想要的知识。
使用tkinter和sqlite3方法编写
import tkinter as tk
from tkinter import simpledialog, messagebox
import sqlite3
class DeviceManagementApp:
def __init__(self, root):
self.root = root
self.root.title("设备管理系统")
self.root.geometry("400x300")
# 创建四个按钮,每个按钮对应一个模块
btn_add = tk.Button(root, text="增加设备", command=self.show_add_device_window)
btn_add.pack(pady=10)
btn_delete = tk.Button(root, text="删除设备", command=self.delete_device)
btn_delete.pack(pady=10)
btn_edit = tk.Button(root, text="修改设备", command=self.edit_device)
btn_edit.pack(pady=10)
btn_reserve = tk.Button(root, text="预约设备", command=self.reserve_device)
btn_reserve.pack(pady=10)
btn_view_devices = tk.Button(root, text="查看设备", command=self.show_all_devices)
btn_view_devices.pack(pady=10)
# 初始化数据库
self.initialize_database()
# 添加输入框作为实例变量
self.entry_device_number = None
self.entry_device_type = None
self.entry_device_name = None
self.entry_device_price = None
self.entry_purchase_date = None
self.entry_is_scrapped = None
self.entry_scrap_date = None
def initialize_database(self):
self.conn = sqlite3.connect("devices.db")
self.cursor = self.conn.cursor()
# 创建设备表
self.cursor.execute('''
CREATE TABLE IF NOT EXISTS devices (
id INTEGER PRIMARY KEY AUTOINCREMENT,
device_number TEXT NOT NULL,
device_type TEXT NOT NULL,
device_name TEXT NOT NULL,
device_price REAL NOT NULL,
purchase_date DATE NOT NULL,
is_scrapped BOOLEAN NOT NULL,
scrap_date DATE,
is_reserved BOOLEAN DEFAULT 0, -- 添加默认值
UNIQUE(device_number)
)
''')
self.conn.commit()
def show_add_device_window(self):
add_device_window = tk.Toplevel(self.root)
add_device_window.title("增加设备")
add_device_window.geometry("300x250")
# 创建输入框和标签
tk.Label(add_device_window, text="设备编号:").pack(pady=5)
self.entry_device_number = tk.Entry(add_device_window)
self.entry_device_number.pack(pady=5)
tk.Label(add_device_window, text="设备种类:").pack(pady=5)
self.entry_device_type = tk.Entry(add_device_window)
self.entry_device_type.pack(pady=5)
tk.Label(add_device_window, text="设备名称:").pack(pady=5)
self.entry_device_name = tk.Entry(add_device_window)
self.entry_device_name.pack(pady=5)
tk.Label(add_device_window, text="设备价格:").pack(pady=5)
self.entry_device_price = tk.Entry(add_device_window)
self.entry_device_price.pack(pady=5)
tk.Label(add_device_window, text="购入日期:").pack(pady=5)
self.entry_purchase_date = tk.Entry(add_device_window)
self.entry_purchase_date.pack(pady=5)
tk.Label(add_device_window, text="是否报废:").pack(pady=5)
self.entry_is_scrapped = tk.Entry(add_device_window)
self.entry_is_scrapped.pack(pady=5)
tk.Label(add_device_window, text="报废日期:").pack(pady=5)
self.entry_scrap_date = tk.Entry(add_device_window)
self.entry_scrap_date.pack(pady=5)
# 创建确认按钮
tk.Button(add_device_window, text="确认", command=self.add_device).pack(pady=10)
def add_device(self):
device_number = self.entry_device_number.get()
device_type = self.entry_device_type.get()
device_name = self.entry_device_name.get()
device_price = self.entry_device_price.get()
purchase_date = self.entry_purchase_date.get()
is_scrapped = self.entry_is_scrapped.get()
scrap_date = self.entry_scrap_date.get()
# 检查设备编号是否已经存在
self.cursor.execute("SELECT COUNT(*) FROM devices WHERE device_number=?", (device_number,))
count = self.cursor.fetchone()[0]
if count > 0:
messagebox.showerror("错误", f"设备编号'{device_number}'已存在,请输入唯一的设备编号。")
return
try:
# 将设备信息插入数据库
self.cursor.execute(
"INSERT INTO devices (device_number, device_type, device_name, device_price, purchase_date, is_scrapped, scrap_date) VALUES (?, ?, ?, ?, ?, ?, ?)",
(device_number, device_type, device_name, device_price, purchase_date, is_scrapped, scrap_date)
)
self.conn.commit()
messagebox.showinfo("成功", f"设备'{device_name}'添加成功!")
except sqlite3.IntegrityError:
messagebox.showerror("错误", f"设备编号'{device_number}'已存在,请输入唯一的设备编号。")
def delete_device(self):
# 创建删除设备的窗口
delete_device_window = tk.Toplevel(self.root)
delete_device_window.title("删除设备")
delete_device_window.geometry("300x150")
# 创建输入框和标签
tk.Label(delete_device_window, text="设备编号:").pack(pady=5)
entry_device_number = tk.Entry(delete_device_window)
entry_device_number.pack(pady=5)
# 创建确认按钮
tk.Button(delete_device_window, text="确认删除",
command=lambda: self.confirm_delete_device(entry_device_number.get(), delete_device_window)).pack(
pady=10)
def confirm_delete_device(self, device_number, delete_device_window):
try:
# 在数据库中删除相应设备信息
self.cursor.execute("DELETE FROM devices WHERE device_number=?", (device_number,))
self.conn.commit()
messagebox.showinfo("成功", f"设备编号'{device_number}'删除成功!")
# 关闭删除设备的窗口
delete_device_window.destroy()
# 刷新设备信息
self.show_all_devices()
except Exception as e:
messagebox.showerror("错误", f"删除设备失败:{str(e)}")
def edit_device(self):
# 创建修改设备的窗口
edit_device_window = tk.Toplevel(self.root)
edit_device_window.title("修改设备")
edit_device_window.geometry("300x150")
# 创建输入框和标签
tk.Label(edit_device_window, text="设备编号:").pack(pady=5)
entry_device_number = tk.Entry(edit_device_window)
entry_device_number.pack(pady=5)
# 创建确认按钮
tk.Button(edit_device_window, text="确认修改",
command=lambda: self.confirm_edit_device(entry_device_number.get(), edit_device_window)).pack(pady=10)
def confirm_edit_device(self, device_number, edit_device_window):
# 在数据库中查询相应设备信息
self.cursor.execute("SELECT * FROM devices WHERE device_number=?", (device_number,))
device_info = self.cursor.fetchone()
if device_info:
# 关闭修改设备的窗口
edit_device_window.destroy()
# 打开设备信息修改页面
self.show_edit_device_info(device_info)
else:
messagebox.showerror("错误", f"设备编号'{device_number}'不存在,请输入正确的设备编号。")
def show_edit_device_info(self, device_info):
# 创建设备信息修改的窗口
edit_info_window = tk.Toplevel(self.root)
edit_info_window.title("修改设备信息")
edit_info_window.geometry("400x300")
# 创建输入框和标签,并设置默认值为当前设备信息
tk.Label(edit_info_window, text="设备编号:").grid(row=0, column=0, pady=5)
entry_device_number = tk.Entry(edit_info_window)
entry_device_number.grid(row=0, column=1, pady=5)
entry_device_number.insert(0, device_info[1])
tk.Label(edit_info_window, text="设备种类:").grid(row=1, column=0, pady=5)
entry_device_type = tk.Entry(edit_info_window)
entry_device_type.grid(row=1, column=1, pady=5)
entry_device_type.insert(0, device_info[2])
tk.Label(edit_info_window, text="设备名称:").grid(row=2, column=0, pady=5)
entry_device_name = tk.Entry(edit_info_window)
entry_device_name.grid(row=2, column=1, pady=5)
entry_device_name.insert(0, device_info[3])
tk.Label(edit_info_window, text="设备价格:").grid(row=3, column=0, pady=5)
entry_device_price = tk.Entry(edit_info_window)
entry_device_price.grid(row=3, column=1, pady=5)
entry_device_price.insert(0, device_info[4])
tk.Label(edit_info_window, text="购入日期:").grid(row=4, column=0, pady=5)
entry_purchase_date = tk.Entry(edit_info_window)
entry_purchase_date.grid(row=4, column=1, pady=5)
entry_purchase_date.insert(0, device_info[5])
tk.Label(edit_info_window, text="是否报废:").grid(row=5, column=0, pady=5)
entry_is_scrapped = tk.Entry(edit_info_window)
entry_is_scrapped.grid(row=5, column=1, pady=5)
entry_is_scrapped.insert(0, device_info[6])
tk.Label(edit_info_window, text="报废日期:").grid(row=6, column=0, pady=5)
entry_scrap_date = tk.Entry(edit_info_window)
entry_scrap_date.grid(row=6, column=1, pady=5)
entry_scrap_date.insert(0, device_info[7])
# 创建确认按钮
tk.Button(edit_info_window, text="确认",
command=lambda: self.confirm_save_edit(device_info[0], entry_device_number.get(),
entry_device_type.get(), entry_device_name.get(),
entry_device_price.get(), entry_purchase_date.get(),
entry_is_scrapped.get(), entry_scrap_date.get(),
edit_info_window)).grid(row=7, columnspan=2, pady=10)
def confirm_save_edit(self, device_id, new_device_number, new_device_type, new_device_name, new_device_price,
new_purchase_date, new_is_scrapped, new_scrap_date, edit_info_window):
try:
# 更新数据库中的设备信息
self.cursor.execute(
"UPDATE devices SET device_number=?, device_type=?, device_name=?, device_price=?, purchase_date=?, is_scrapped=?, scrap_date=? WHERE id=?",
(new_device_number, new_device_type, new_device_name, new_device_price, new_purchase_date,
new_is_scrapped, new_scrap_date, device_id)
)
self.conn.commit()
messagebox.showinfo("成功", f"设备信息修改成功!")
# 关闭设备信息修改的窗口
edit_info_window.destroy()
# 刷新设备信息
self.show_all_devices()
except Exception as e:
messagebox.showerror("错误", f"修改设备信息失败:{str(e)}")
def reserve_device(self):
# 创建预约设备的窗口
reserve_device_window = tk.Toplevel(self.root)
reserve_device_window.title("预约设备")
reserve_device_window.geometry("300x150")
# 创建选择框和确认按钮
choice_var = tk.StringVar()
tk.Radiobutton(reserve_device_window, text="预约设备", variable=choice_var, value="reserve").pack(pady=5)
tk.Radiobutton(reserve_device_window, text="释放设备", variable=choice_var, value="release").pack(pady=5)
# 创建确认按钮
tk.Button(reserve_device_window, text="确认",
command=lambda: self.confirm_reserve_or_release(choice_var.get(), reserve_device_window)).pack(
pady=10)
def confirm_reserve_or_release(self, choice, reserve_device_window):
# 关闭预约设备的窗口
reserve_device_window.destroy()
# 根据选择创建预约/释放设备的窗口
if choice == "reserve":
self.show_reserve_device_window()
elif choice == "release":
self.show_release_device_window()
def show_reserve_device_window(self):
# 创建预约设备的窗口
reserve_window = tk.Toplevel(self.root)
reserve_window.title("预约设备")
reserve_window.geometry("300x150")
# 创建输入框和标签
tk.Label(reserve_window, text="设备编号:").pack(pady=5)
entry_device_number = tk.Entry(reserve_window)
entry_device_number.pack(pady=5)
# 创建确认按钮
tk.Button(reserve_window, text="确认预约",
command=lambda: self.confirm_reserve_device(entry_device_number.get(), reserve_window)).pack(pady=10)
def show_release_device_window(self):
# 创建释放设备的窗口
release_window = tk.Toplevel(self.root)
release_window.title("释放设备")
release_window.geometry("300x150")
# 创建输入框和标签
tk.Label(release_window, text="设备编号:").pack(pady=5)
entry_device_number = tk.Entry(release_window)
entry_device_number.pack(pady=5)
# 创建确认按钮
tk.Button(release_window, text="确认释放",
command=lambda: self.confirm_release_device(entry_device_number.get(), release_window)).pack(pady=10)
def confirm_reserve_device(self, device_number, reserve_window):
try:
# 查询设备是否已被预约
self.cursor.execute("SELECT is_reserved FROM devices WHERE device_number=?", (device_number,))
is_reserved = self.cursor.fetchone()[0]
if not is_reserved:
# 更新数据库中的设备信息,将设备设置为已预约
self.cursor.execute("UPDATE devices SET is_reserved=1 WHERE device_number=?", (device_number,))
self.conn.commit()
messagebox.showinfo("成功", f"设备编号'{device_number}'预约成功!")
# 关闭预约设备的窗口
reserve_window.destroy()
# 刷新设备信息
self.show_all_devices()
else:
messagebox.showerror("错误", f"设备编号'{device_number}'已被预约,请选择其他设备。")
except Exception as e:
messagebox.showerror("错误", f"预约设备失败:{str(e)}")
def confirm_release_device(self, device_number, release_window):
try:
# 查询设备是否已被预约
self.cursor.execute("SELECT is_reserved FROM devices WHERE device_number=?", (device_number,))
is_reserved = self.cursor.fetchone()[0]
if is_reserved:
# 更新数据库中的设备信息,将设备设置为未预约
self.cursor.execute("UPDATE devices SET is_reserved=0 WHERE device_number=?", (device_number,))
self.conn.commit()
messagebox.showinfo("成功", f"设备编号'{device_number}'释放成功!")
# 关闭释放设备的窗口
release_window.destroy()
# 刷新设备信息
self.show_all_devices()
else:
messagebox.showinfo("提示", f"设备编号'{device_number}'未被预约,无需释放。")
except Exception as e:
messagebox.showerror("错误", f"释放设备失败:{str(e)}")
def show_all_devices(self):
# 创建一个新的窗口用于显示设备信息
view_devices_window = tk.Toplevel(self.root)
view_devices_window.title("查看设备")
view_devices_window.geometry("500x400")
# 创建一个文本框用于显示设备信息
text_box = tk.Text(view_devices_window, wrap=tk.WORD)
text_box.pack(pady=10)
# 查询数据库,获取所有设备信息
self.cursor.execute("SELECT * FROM devices")
devices = self.cursor.fetchall()
# 在文本框中显示设备信息
for device in devices:
text_box.insert(tk.END, f"设备编号: {device[1]}\n")
text_box.insert(tk.END, f"设备种类: {device[2]}\n")
text_box.insert(tk.END, f"设备名称: {device[3]}\n")
text_box.insert(tk.END, f"设备价格: {device[4]}\n")
text_box.insert(tk.END, f"购入日期: {device[5]}\n")
text_box.insert(tk.END, f"是否报废: {device[6]}\n")
text_box.insert(tk.END, f"报废日期: {device[7]}\n\n")
# 设为只读
text_box.config(state=tk.DISABLED)
def show_message(self, title, message):
messagebox.showinfo(title, message)
def has_devices(self):
self.cursor.execute("SELECT COUNT(*) FROM devices")
count = self.cursor.fetchone()[0]
return count > 0
if __name__ == "__main__":
root = tk.Tk()
app = DeviceManagementApp(root)
root.mainloop()
5.1测试用例
测试使用了一下数据
设备编号 | 设备种类 | 设备名称 | 设备价格 | 购入日期 | 是否报废 | 报废日期 |
1 | 打印机 | 墨盒 | 20.0 | 2023-1-1 | 是 | 2023-2-1 |
2 | 计算机 | 硬盘 | 1000.0 | 2023-12-23 | 否 | 否 |
3 | 计算机 | 主板 | 500.0 | 2022-2-5 | 是 | 2023-1-9 |
4 | 计算机 | 主板 | 200.0 | 2023-2-5 | 否 | None |
5 | 计算机 | 主板 | 8000.0 | 2023-2-5 | 否 | None |
程序运行结果
1.程序整体模块
![](https://img-blog.csdnimg.cn/direct/949a85549016409ca4ebf5f7db3757c6.png)
图表 1exe文件运行页面
2.设备信息录入模块:
在点击增加设备后,出现一个独立页面显示需要添加的信息,使用者需要手动添加相应信息后确认。
![](https://img-blog.csdnimg.cn/direct/abdd9a819fa643e1bdf625276b2b6293.png)
图表 2增加设备
输入相应设备信息
![](https://img-blog.csdnimg.cn/direct/0105d1a60d17491290465163c21fa540.png)
图表 3加入一个设备信息
如果之前没有添加过此编号的设备信息,则会显示添加成功提示信息
![](https://img-blog.csdnimg.cn/direct/de7d414814024dd2912271f53e4d3d3e.png)
图表 4添加成功提示
如果之前添加过此编号设备信息,则会显示已存在,并提示重新输入
![](https://img-blog.csdnimg.cn/direct/236d0019e5ec47a48186f254d9b62c6e.png)
图表 5添加错误提示
之后就可以在程序中添加入相应信息。
3.设备信息删除模块:
![](https://img-blog.csdnimg.cn/direct/33e0569be45e4d03bc7c86a485e0af14.png)
图表 6删除前设备总体信息
删除设备时,首先需要点击删除设备,并且会出现页面提示需要删除设备的编号
![](https://img-blog.csdnimg.cn/direct/9108e5d1fe4e45b991298576d64fe65f.png)
图表 7输入删除设备编号
之后会显示删除成功,并且相应的信息也会删除
![](https://img-blog.csdnimg.cn/direct/87beb99f7f5c4341bb9e06e613c022c4.png)
图表 8删除成功提示信息
![](https://img-blog.csdnimg.cn/direct/ff6443f9c5d3409584870924a020f4ff.png)
图表 9删除后信息页面
4.设备信息修改模块:
![](https://img-blog.csdnimg.cn/direct/f78e46281b0c4227b4d0d27fb5fda016.png)
图表 10修改前信息
信息修改模块,点击信息修改后,需要使用者输入想要修改信息的编号,并且如果不存在这个设备,会提示此设备不存在
![](https://img-blog.csdnimg.cn/direct/9b4cf63041d147a0a8bb10a0e3192e57.png)
图表 11不存在提示页面
若存在则可以进行修改其中信息
![](https://img-blog.csdnimg.cn/direct/ab8c7766d7d44d23a334164777076162.png)
图表 12修改信息页面
修改成功后,信息同步到数据库中
![](https://img-blog.csdnimg.cn/direct/db419865cd544e698891f3a56fa0fcc0.png)
图表 13更新后信息
5.设备预约与释放模块:
点击预约设备后,可以选择预约或者释放设备
![](https://img-blog.csdnimg.cn/direct/4914e9da987b4100b7b4de6735cf115a.png)
图表 14选择页面
![](https://img-blog.csdnimg.cn/direct/f1dd8bb25bed4a1baf791043b6473e06.png)
图表 15选择预约或释放编号
如果设备被预约中,则无法预约,需要释放设备后才可以预约,同样的,如果设备想要释放,则需要正在预约中,否则也会释放失败,并且释放与预约时必须是存在的设备,否则也会提示错误
6.设备信息查看模块
点击查看设备按钮,则可以查看当前的所有设备信息
![](https://img-blog.csdnimg.cn/direct/acea4dd3102042509258aacf3202e8b1.png)
图表 16设备信息
技术力不强,并且代码存在一定bug,望谅解