前言

这里简单分享一个使用pyQT写一个图书管理系统,并给出思路以及用到的工具,每个模块得到源码


系统设计思路

1
2
3
4
5
6
7
8
9
graph TD
A[主界面] --> B[数据库模块]
A --> C[图书管理模块]
C --> D[添加图书]
C --> E[删除图书]
C --> F[修改图书]
C --> G[查询图书]
A --> H[表格展示模块]
B --> I[SQLite数据库]

功能模块划分

  1. 数据库模块:负责数据库连接和图书数据操作
  2. 主界面模块:构建GUI界面和布局
  3. 图书管理模块:实现增删改查业务逻辑
  4. 表格展示模块:使用QTableView展示图书数据

分块实现

1. 导入依赖库

1
2
3
4
5
6
import sys
import sqlite3
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout, QHBoxLayout,
QTableView, QPushButton, QLineEdit, QLabel, QMessageBox, QHeaderView)
from PyQt5.QtGui import QStandardItemModel, QStandardItem
from PyQt5.QtCore import Qt

2. 数据库模块

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
class BookDatabase:
def __init__(self, db_name="library.db"):
"""初始化数据库连接"""
self.conn = sqlite3.connect(db_name) # 连接SQLite数据库
self.create_table() # 创建数据表

def create_table(self):
"""创建图书数据表"""
cursor = self.conn.cursor()
cursor.execute('''
CREATE TABLE IF NOT EXISTS books (
id INTEGER PRIMARY KEY AUTOINCREMENT,
title TEXT NOT NULL,
author TEXT NOT NULL,
isbn TEXT UNIQUE,
publish_year INTEGER,
quantity INTEGER DEFAULT 0
)
''') # 图书表包含ID、书名、作者、ISBN、出版年份和数量字段
self.conn.commit()

def add_book(self, title, author, isbn, year, quantity):
"""添加新图书"""
cursor = self.conn.cursor()
try:
cursor.execute('''
INSERT INTO books (title, author, isbn, publish_year, quantity)
VALUES (?, ?, ?, ?, ?)
''', (title, author, isbn, year, quantity))
self.conn.commit()
return True
except sqlite3.IntegrityError:
return False # ISBN重复时返回False

def delete_book(self, book_id):
"""根据ID删除图书"""
cursor = self.conn.cursor()
cursor.execute("DELETE FROM books WHERE id = ?", (book_id,))
self.conn.commit()
return cursor.rowcount > 0 # 返回是否成功删除

def update_book(self, book_id, title, author, isbn, year, quantity):
"""更新图书信息"""
cursor = self.conn.cursor()
cursor.execute('''
UPDATE books
SET title=?, author=?, isbn=?, publish_year=?, quantity=?
WHERE id=?
''', (title, author, isbn, year, quantity, book_id))
self.conn.commit()
return cursor.rowcount > 0 # 返回是否成功更新

def search_books(self, keyword=""):
"""搜索图书(支持模糊查询)"""
cursor = self.conn.cursor()
# 使用SQL LIKE实现模糊搜索
query = '''
SELECT * FROM books
WHERE title LIKE ? OR author LIKE ? OR isbn LIKE ?
'''
cursor.execute(query, (f"%{keyword}%", f"%{keyword}%", f"%{keyword}%"))
return cursor.fetchall() # 返回所有匹配结果

def get_all_books(self):
"""获取所有图书"""
cursor = self.conn.cursor()
cursor.execute("SELECT * FROM books ORDER BY title")
return cursor.fetchall()

def close(self):
"""关闭数据库连接"""
self.conn.close()

3. 主界面类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
class LibraryApp(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("图书管理系统") # 设置窗口标题
self.resize(800, 600) # 设置初始窗口大小

# 初始化数据库
self.db = BookDatabase()

# 创建中央部件和布局
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout()
central_widget.setLayout(main_layout)

# 创建搜索区域
search_layout = QHBoxLayout()
self.search_input = QLineEdit()
self.search_input.setPlaceholderText("输入书名、作者或ISBN...")
search_button = QPushButton("搜索")
search_button.clicked.connect(self.search_books)
search_layout.addWidget(self.search_input)
search_layout.addWidget(search_button)
main_layout.addLayout(search_layout)

# 创建表格视图
self.table_view = QTableView()
self.table_model = QStandardItemModel() # 创建数据模型
self.setup_table() # 初始化表格
main_layout.addWidget(self.table_view)

# 创建按钮区域
button_layout = QHBoxLayout()
self.add_button = QPushButton("添加图书")
self.edit_button = QPushButton("修改图书")
self.delete_button = QPushButton("删除图书")
self.refresh_button = QPushButton("刷新列表")

# 连接按钮信号
self.add_button.clicked.connect(self.show_add_dialog)
self.edit_button.clicked.connect(self.show_edit_dialog)
self.delete_button.clicked.connect(self.delete_book)
self.refresh_button.clicked.connect(self.load_books)

button_layout.addWidget(self.add_button)
button_layout.addWidget(self.edit_button)
button_layout.addWidget(self.delete_button)
button_layout.addWidget(self.refresh_button)
main_layout.addLayout(button_layout)

# 加载图书数据
self.load_books()

def setup_table(self):
"""配置表格视图"""
self.table_model.setHorizontalHeaderLabels(
["ID", "书名", "作者", "ISBN", "出版年份", "数量"]
)
self.table_view.setModel(self.table_model)

# 设置表格属性
self.table_view.setSelectionBehavior(QTableView.SelectRows) # 整行选择
self.table_view.setEditTriggers(QTableView.NoEditTriggers) # 禁止直接编辑
self.table_view.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch) # 自动拉伸列宽

def load_books(self):
"""加载所有图书到表格"""
self.table_model.removeRows(0, self.table_model.rowCount()) # 清空现有数据
books = self.db.get_all_books()

for book in books:
row = [
QStandardItem(str(book[0])), # ID
QStandardItem(book[1]), # 书名
QStandardItem(book[2]), # 作者
QStandardItem(book[3]), # ISBN
QStandardItem(str(book[4])), # 出版年份
QStandardItem(str(book[5])) # 数量
]
self.table_model.appendRow(row)

def search_books(self):
"""搜索图书并刷新表格"""
keyword = self.search_input.text().strip()
books = self.db.search_books(keyword)
self.table_model.removeRows(0, self.table_model.rowCount())

for book in books:
row = [
QStandardItem(str(book[0])),
QStandardItem(book[1]),
QStandardItem(book[2]),
QStandardItem(book[3]),
QStandardItem(str(book[4])),
QStandardItem(str(book[5]))
]
self.table_model.appendRow(row)

def get_selected_book_id(self):
"""获取当前选中图书的ID"""
selected = self.table_view.selectionModel().selectedRows()
if selected:
index = selected[0].row()
return int(self.table_model.item(index, 0).text()) # 获取ID列的值
return None

def show_add_dialog(self):
"""显示添加图书对话框"""
dialog = BookDialog(self)
if dialog.exec_() == BookDialog.Accepted:
# 获取对话框中的数据
data = dialog.get_data()
success = self.db.add_book(*data)

if success:
QMessageBox.information(self, "成功", "图书添加成功!")
self.load_books() # 刷新列表
else:
QMessageBox.warning(self, "错误", "添加失败:ISBN已存在!")

def show_edit_dialog(self):
"""显示编辑图书对话框"""
book_id = self.get_selected_book_id()
if not book_id:
QMessageBox.warning(self, "警告", "请先选择要编辑的图书")
return

# 获取图书当前信息
book = self.get_book_by_id(book_id)
if not book:
return

dialog = BookDialog(self, edit_mode=True)
dialog.set_data(book) # 填充当前数据

if dialog.exec_() == BookDialog.Accepted:
data = dialog.get_data()
# 更新数据(跳过ID)
success = self.db.update_book(book_id, *data)

if success:
QMessageBox.information(self, "成功", "图书信息更新成功!")
self.load_books()
else:
QMessageBox.warning(self, "错误", "更新失败,请检查数据")

def delete_book(self):
"""删除选中图书"""
book_id = self.get_selected_book_id()
if not book_id:
QMessageBox.warning(self, "警告", "请先选择要删除的图书")
return

reply = QMessageBox.question(
self, "确认删除",
"确定要删除这本图书吗?此操作不可恢复!",
QMessageBox.Yes | QMessageBox.No
)

if reply == QMessageBox.Yes:
success = self.db.delete_book(book_id)
if success:
QMessageBox.information(self, "成功", "图书已删除")
self.load_books()
else:
QMessageBox.warning(self, "错误", "删除失败,图书不存在")

def get_book_by_id(self, book_id):
"""根据ID获取图书详细信息"""
cursor = self.db.conn.cursor()
cursor.execute("SELECT * FROM books WHERE id=?", (book_id,))
return cursor.fetchone()

def closeEvent(self, event):
"""重写关闭事件,确保关闭数据库连接"""
self.db.close()
event.accept()

4. 图书对话框类(用于添加/编辑)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
class BookDialog(QDialog):
def __init__(self, parent=None, edit_mode=False):
super().__init__(parent)
self.setWindowTitle("编辑图书" if edit_mode else "添加图书")
self.setFixedSize(400, 300)

layout = QVBoxLayout()
self.setLayout(layout)

# 创建表单字段
form_layout = QFormLayout()

self.title_input = QLineEdit()
self.author_input = QLineEdit()
self.isbn_input = QLineEdit()
self.year_input = QLineEdit()
self.quantity_input = QLineEdit()

# 设置输入验证
self.year_input.setValidator(QIntValidator(1000, 2100, self)) # 年份范围
self.quantity_input.setValidator(QIntValidator(0, 999, self)) # 数量范围

form_layout.addRow("书名*:", self.title_input)
form_layout.addRow("作者*:", self.author_input)
form_layout.addRow("ISBN*:", self.isbn_input)
form_layout.addRow("出版年份:", self.year_input)
form_layout.addRow("数量:", self.quantity_input)

layout.addLayout(form_layout)

# 创建按钮
button_box = QDialogButtonBox(
QDialogButtonBox.Ok | QDialogButtonBox.Cancel
)
button_box.accepted.connect(self.validate)
button_box.rejected.connect(self.reject)

layout.addWidget(button_box)

def validate(self):
"""验证表单数据"""
title = self.title_input.text().strip()
author = self.author_input.text().strip()
isbn = self.isbn_input.text().strip()

if not title or not author or not isbn:
QMessageBox.warning(self, "输入错误", "带*号的字段不能为空")
return

self.accept() # 所有验证通过,关闭对话框

def get_data(self):
"""获取表单数据"""
return (
self.title_input.text().strip(),
self.author_input.text().strip(),
self.isbn_input.text().strip(),
int(self.year_input.text() or 0),
int(self.quantity_input.text() or 0)
)

def set_data(self, book_data):
"""填充表单数据(编辑模式)"""
# book_data格式: (id, title, author, isbn, year, quantity)
self.title_input.setText(book_data[1])
self.author_input.setText(book_data[2])
self.isbn_input.setText(book_data[3])
self.year_input.setText(str(book_data[4]))
self.quantity_input.setText(str(book_data[5]))

5. 应用启动

1
2
3
4
5
if __name__ == "__main__":
app = QApplication(sys.argv)
window = LibraryApp()
window.show()
sys.exit(app.exec_())

使用指南

功能说明

  1. 添加图书:点击”添加图书”按钮,填写必填信息(书名、作者、ISBN)
  2. 修改图书:选中图书后点击”修改图书”,编辑信息
  3. 删除图书:选中图书后点击”删除图书”,确认删除
  4. 搜索功能:在搜索框输入关键词,支持书名/作者/ISBN模糊匹配
  5. 刷新列表:点击”刷新列表”按钮重置显示

安装与运行

  1. 安装依赖:
1
pip install pyqt5 sqlite3
  1. 运行程序:
1
python library_app.py
  1. 初始界面:
1
2
3
4
5
6
7
8
9
10
11
+-----------------------------------------+
| 图书管理系统 |
|-----------------------------------------|
| [搜索框] [搜索按钮] |
|-----------------------------------------|
| ID | 书名 | 作者 | ISBN | 年份 | 数量 |
|-----------------------------------------|
| ...(图书列表)... |
|-----------------------------------------|
| [添加] [修改] [删除] [刷新] |
+-----------------------------------------+

总结

技术要点总结

模块 关键技术 实现说明
数据库 SQLite3 轻量级嵌入式数据库
UI框架 PyQt5 跨平台GUI开发框架
数据展示 QTableView + QStandardItemModel Model-View架构
数据验证 QValidator 输入内容验证
对话框 QDialog 模态对话框交互

扩展建议

  1. 用户认证:添加登录系统,区分管理员和普通用户
  2. 借阅管理:扩展借阅记录功能,添加读者表
  3. 数据导入导出:支持Excel/CSV格式导入导出
  4. 报表生成:添加借阅统计、库存报表
  5. 多语言支持:使用Qt翻译系统实现国际化
  6. 主题切换:添加暗色/亮色模式切换