(Python设计图书馆管理系统技术文档(四))
5.设计和代码
- (接上篇)
5.2 用户系统使用
5.2.1 用户界面(StudentHome.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import QIcon, QFont
import qdarkstyle
import sip
from BookStorageViewer import BookStorageViewer
from borrowBookDialog import borrowBookDialog
from returnBookDialog import returnBookDialog
from BorrowStatusViewer import BorrowStatusViewer
class StudentHome(QWidget):
def __init__(self, studentId):
super().__init__()
self.StudentId = studentId
self.resize(900, 600)
self.setWindowTitle("欢迎使用图书馆管理系统")
self.setUpUI()
def setUpUI(self):
# 总布局
self.layout = QHBoxLayout(self)
# 按钮布局
self.buttonLayout = QVBoxLayout()
# 按钮控件(借书、还书、借阅状态、所有书籍),放置到垂直布局并设定字体等风格样式
self.borrowBookButton = QPushButton("借书")
self.returnBookButton = QPushButton("还书")
self.myBookStatus = QPushButton("借阅状态")
self.allBookButton = QPushButton("所有书籍")
self.buttonLayout.addWidget(self.borrowBookButton)
self.buttonLayout.addWidget(self.returnBookButton)
self.buttonLayout.addWidget(self.myBookStatus)
self.buttonLayout.addWidget(self.allBookButton)
self.borrowBookButton.setFixedWidth(100)
self.borrowBookButton.setFixedHeight(42)
self.returnBookButton.setFixedWidth(100)
self.returnBookButton.setFixedHeight(42)
self.myBookStatus.setFixedWidth(100)
self.myBookStatus.setFixedHeight(42)
self.allBookButton.setFixedWidth(100)
self.allBookButton.setFixedHeight(42)
font = QFont()
font.setPixelSize(16)
self.borrowBookButton.setFont(font)
self.returnBookButton.setFont(font)
self.myBookStatus.setFont(font)
self.allBookButton.setFont(font)
# 实例化一个书籍库存预览的对象并调用
# 实例化一个借阅状态的对象并调用
# 把所有书籍按钮设为不可用,不然会出现分屏的情况
self.storageView = BookStorageViewer()
self.borrowStatusView = BorrowStatusViewer(self.StudentId)
self.allBookButton.setEnabled(False)
# 把上面的按钮布局和书籍库存预览放到水平布局中
self.layout.addLayout(self.buttonLayout)
self.layout.addWidget(self.storageView)
# 信号与槽的绑定:四个按钮与相应事件的对应
self.borrowBookButton.clicked.connect(self.borrowBookButtonClicked)
self.returnBookButton.clicked.connect(self.returnBookButtonClicked)
self.myBookStatus.clicked.connect(self.myBookStatusClicked)
self.allBookButton.clicked.connect(self.allBookButtonClicked)
# 信号槽函数:借书的dialog
def borrowBookButtonClicked(self):
borrowDialog = borrowBookDialog(self.StudentId, self)
borrowDialog.borrow_book_success_signal.connect(self.borrowStatusView.borrowedQuery)
borrowDialog.borrow_book_success_signal.connect(self.storageView.searchButtonClicked)
borrowDialog.show()
borrowDialog.exec_()
return
# 信号槽函数:还书的dialog
def returnBookButtonClicked(self):
returnDialog = returnBookDialog(self.StudentId, self)
returnDialog.return_book_success_signal.connect(self.borrowStatusView.returnedQuery)
returnDialog.return_book_success_signal.connect(self.borrowStatusView.borrowedQuery)
returnDialog.return_book_success_signal.connect(self.storageView.searchButtonClicked)
returnDialog.show()
returnDialog.exec_()
# 槽函数:借阅状态的切换和查询
def myBookStatusClicked(self):
self.layout.removeWidget(self.storageView)
sip.delete(self.storageView)
self.storageView = BookStorageViewer()
self.borrowStatusView = BorrowStatusViewer(self.StudentId)
self.layout.addWidget(self.borrowStatusView)
self.allBookButton.setEnabled(True)
self.myBookStatus.setEnabled(False)
return
# 槽函数:关掉借阅状态切换至所有书籍并展示分页信息
def allBookButtonClicked(self):
self.layout.removeWidget(self.borrowStatusView)
sip.delete(self.borrowStatusView)
self.borrowStatusView = BorrowStatusViewer(self.StudentId)
self.storageView = BookStorageViewer()
self.layout.addWidget(self.storageView)
self.allBookButton.setEnabled(False)
self.myBookStatus.setEnabled(True)
return
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
mainWindow = StudentHome("PB15000139")
mainWindow.show()
sys.exit(app.exec_())
- 代码分析
- 这个窗体的布局相对前面的简单多了。一个水平布局,左侧放置一个垂直布局,垂直布局里面放置4个按钮;右侧放置所有书籍的预览界面,点击借阅状态后,这个地方还可以展示上下垂直布局的借阅状态。效果如图。
- 再4个信号与槽函数的使用。前两个同时还是信号函数,连接到外部的槽函数,弹出新的对话框;后两个是槽函数,调用外部类方法,展示新的页面。注意,每个槽函数同时也是信号函数,调用外部类的方法。
-
- 借书
graph TD A[发送者: borrowBookButton] -- 信号: clicked--> B((连接: connect))--接收 --> C(接受者:borrowBookButtonClicked)--调用: get-->D(槽函数: borrowBookDialog)
- 还书
graph TD A[发送者: returnBookButton] -- 信号: clicked--> B((连接: connect))--接收 --> C(接受者:returnBookButtonClicked)--调用: get-->D(槽函数: returnBookDialog)
- 借阅状态
graph TD A[发送者: myBookStatus] -- 信号: clicked--> B((连接: connect))--接收 --> C(接受者:myBookStatusClicked)--调用: get-->D(槽函数: BorrowStatusViewer)
- 所有书籍
graph TD A[发送者: allBookButton] -- 信号: clicked--> B((连接: connect))--接收 --> C(接受者:allBookButtonClicked)--调用: get-->D(槽函数: borrowBookDialog)
5.2.2 查询书籍(BookStorageViewer.py)
# -*- coding: utf-8 -*-
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
import qdarkstyle
from PyQt5.QtSql import *
class BookStorageViewer(QWidget):
def __init__(self):
super(BookStorageViewer, self).__init__()
self.resize(1300, 500)
self.setWindowTitle("欢迎使用享学图书馆管理系统")
# 查询模型
self.queryModel = None
# 数据表
self.tableView = None
# 当前页
self.currentPage = 0
# 总页数
self.totalPage = 0
# 总记录数
self.totalRecord = 0
# 每页数据数
self.pageRecord = 10
self.setUpUI()
def setUpUI(self):
self.Vlayout = QVBoxLayout()
self.Hlayout_top = QHBoxLayout()
self.Hlayout_bottom = QHBoxLayout()
# Hlayout_top控件的初始化
self.searchEdit = QLineEdit()
self.searchEdit.setFixedHeight(32)
font = QFont()
font.setPixelSize(15)
self.searchEdit.setFont(font)
self.searchButton = QPushButton("查询")
self.searchButton.setFixedHeight(32)
self.searchButton.setFont(font)
self.searchButton.setIcon(QIcon(QPixmap("./images/search.png")))
self.condisionComboBox = QComboBox()
searchCondision = ['按书名查询', '按书号查询', '按作者查询', '按分类查询', '按出版社查询']
self.condisionComboBox.setFixedHeight(32)
self.condisionComboBox.setFont(font)
self.condisionComboBox.addItems(searchCondision)
self.Hlayout_top.addWidget(self.searchEdit)
self.Hlayout_top.addWidget(self.searchButton)
self.Hlayout_top.addWidget(self.condisionComboBox)
# Hlayout_bottom初始化
self.jumpToLabel = QLabel("跳转到第")
self.pageEdit = QLineEdit()
self.pageEdit.setFixedWidth(30)
s = "/" + str(self.totalPage) + "页"
self.pageLabel = QLabel(s)
self.jumpToButton = QPushButton("跳转")
self.prevButton = QPushButton("前一页")
self.prevButton.setFixedWidth(60)
self.backButton = QPushButton("后一页")
self.backButton.setFixedWidth(60)
Hlayout = QHBoxLayout()
Hlayout.addWidget(self.jumpToLabel)
Hlayout.addWidget(self.pageEdit)
Hlayout.addWidget(self.pageLabel)
Hlayout.addWidget(self.jumpToButton)
Hlayout.addWidget(self.prevButton)
Hlayout.addWidget(self.backButton)
widget = QWidget()
widget.setLayout(Hlayout)
widget.setFixedWidth(500)
self.Hlayout_bottom.addWidget(widget)
# tableView
# 序号,书名,书号,作者,分类,出版社,出版时间,库存,剩余可借
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName('./db/LibraryManagement.db')
self.db.open()
self.tableView = QTableView()
self.tableView.horizontalHeader().setStretchLastSection(True)
self.tableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.queryModel = QSqlQueryModel()
self.searchButtonClicked()
self.tableView.setModel(self.queryModel)
self.queryModel.setHeaderData(0, Qt.Horizontal, "书名")
self.queryModel.setHeaderData(1, Qt.Horizontal, "书号")
self.queryModel.setHeaderData(2, Qt.Horizontal, "作者")
self.queryModel.setHeaderData(3, Qt.Horizontal, "分类")
self.queryModel.setHeaderData(4, Qt.Horizontal, "出版社")
self.queryModel.setHeaderData(5, Qt.Horizontal, "出版时间")
self.queryModel.setHeaderData(6, Qt.Horizontal, "库存")
self.queryModel.setHeaderData(7, Qt.Horizontal, "剩余可借")
self.queryModel.setHeaderData(8, Qt.Horizontal, "总借阅次数")
self.Vlayout.addLayout(self.Hlayout_top)
self.Vlayout.addWidget(self.tableView)
self.Vlayout.addLayout(self.Hlayout_bottom)
self.setLayout(self.Vlayout)
# 信号槽绑定
self.searchButton.clicked.connect(self.searchButtonClicked)
self.prevButton.clicked.connect(self.prevButtonClicked)
self.backButton.clicked.connect(self.backButtonClicked)
self.jumpToButton.clicked.connect(self.jumpToButtonClicked)
self.searchEdit.returnPressed.connect(self.searchButtonClicked)
# 设置窗体底部两个按钮“前一页”、“下一页”的状态
def setButtonStatus(self):
if self.currentPage == self.totalPage:
self.prevButton.setEnabled(True)
self.backButton.setEnabled(False)
if self.currentPage == 1:
self.backButton.setEnabled(True)
self.prevButton.setEnabled(False)
if self.totalPage > self.currentPage > 1:
self.prevButton.setEnabled(True)
self.backButton.setEnabled(True)
# 得到数据总的行数(记录数)
def getTotalRecordCount(self):
self.queryModel.setQuery("SELECT * FROM Book")
self.totalRecord = self.queryModel.rowCount()
return
# 得到总页数
def getPageCount(self):
self.getTotalRecordCount()
# 上取整,如num=(40+10-1)/10就是4页,num=(41+10-1)/10就是5页
# totalRecord查询得到的记录数(根据条件得到部分和总数),pageRecord是一个类常量
self.totalPage = int((self.totalRecord + self.pageRecord - 1) / self.pageRecord)
return
# 分页记录查询,根据条件得到记录数量,以便分布展示
def recordQuery(self, index):
# 1.选定查询书籍的类型(类型字段)
conditionOrCategory = self.condisionComboBox.currentText()
condition = {
'BookName': "按书名查询",
'BookId': "按书号查询",
'Auth': "按作者查询",
'Category': '按分类查询',
'Publisher': '按出版社查询'
}
for k, v in condition.items():
if conditionOrCategory == v:
conditionOrCategory = k
# 2.根据模糊查询条件,得到记录的信息,最后获取查询记录的行数
temp = self.searchEdit.text()
s = '%'
for i in range(0, len(temp)):
s = s + temp[i] + "%"
# 下面语法为查询字段为conditionOrCategory的记录,并按字段conditionOrCategory排序,
# 该字段里面匹配 "%str1%str2%……“这样的文本信息
queryCondition = ("SELECT * FROM Book WHERE %s LIKE '%s' ORDER BY %s " % (
conditionOrCategory, s, conditionOrCategory))
self.queryModel.setQuery(queryCondition)
# 得到查询到的记录数量
self.totalRecord = self.queryModel.rowCount()
# 3.当查询无记录时提醒,再次刷新下面状态栏的记录数
if self.totalRecord == 0:
print(QMessageBox.information(self, "提醒", "查询无记录"))
queryCondition = "select * from Book"
self.queryModel.setQuery(queryCondition)
self.totalRecord = self.queryModel.rowCount()
self.totalPage = int((self.totalRecord + self.pageRecord - 1) / self.pageRecord)
label = "/" + str(int(self.totalPage)) + "页"
self.pageLabel.setText(label)
# 下面语句加了字段排序,然后限定从第几条开始查,查10条
queryCondition = (
"select * from Book ORDER BY %s limit %d,%d "
% (conditionOrCategory, index, self.pageRecord))
self.queryModel.setQuery(queryCondition)
self.setButtonStatus()
return
self.totalPage = int((self.totalRecord + self.pageRecord - 1) / self.pageRecord)
label = "/" + str(int(self.totalPage)) + "页"
self.pageLabel.setText(label)
queryCondition = ("SELECT * FROM Book WHERE %s LIKE '%s' ORDER BY %s LIMIT %d,%d " % (
conditionOrCategory, s, conditionOrCategory, index, self.pageRecord))
self.queryModel.setQuery(queryCondition)
self.setButtonStatus()
return
# 点击查询,查询按钮的槽函数
def searchButtonClicked(self):
self.currentPage = 1
self.pageEdit.setText(str(self.currentPage))
self.getPageCount()
s = "/" + str(int(self.totalPage)) + "页"
self.pageLabel.setText(s)
index = (self.currentPage - 1) * self.pageRecord
self.recordQuery(index)
return
# 向前翻页,前一页按钮的槽函数
def prevButtonClicked(self):
self.currentPage -= 1
if self.currentPage <= 1:
self.currentPage = 1
self.pageEdit.setText(str(self.currentPage))
index = (self.currentPage - 1) * self.pageRecord
self.recordQuery(index)
return
# 向后翻页,后一页按钮的槽函数
def backButtonClicked(self):
self.currentPage += 1
if self.currentPage >= int(self.totalPage):
self.currentPage = int(self.totalPage)
self.pageEdit.setText(str(self.currentPage))
index = (self.currentPage - 1) * self.pageRecord
self.recordQuery(index)
return
# 点击跳转,跳转按钮的槽函数
def jumpToButtonClicked(self):
if self.pageEdit.text().isdigit():
self.currentPage = int(self.pageEdit.text())
if self.currentPage > self.totalPage:
self.currentPage = self.totalPage
if self.currentPage <= 1:
self.currentPage = 1
else:
self.currentPage = 1
index = (self.currentPage - 1) * self.pageRecord
self.pageEdit.setText(str(self.currentPage))
self.recordQuery(index)
return
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
mainWindow = BookStorageViewer()
mainWindow.show()
sys.exit(app.exec_())
- 代码分析
- 第一说明的,还是布局。文字太麻烦,下面两幅图说明。
- 第二是信号与槽的学习。一共有5对信号槽绑定,分别对应“查询”、“前一页”、“后一页”、“跳转”按钮这4个clicked信号的,以及一个“查询文本框”searchEdit里的焦点信号returnPressed的,最后这个功能自然是录入查询信息回车后发送查询信号。这部分代码如下:
# 信号槽绑定 self.searchButton.clicked.connect(self.searchButtonClicked) self.prevButton.clicked.connect(self.prevButtonClicked) self.backButton.clicked.connect(self.backButtonClicked) self.jumpToButton.clicked.connect(self.jumpToButtonClicked) self.searchEdit.returnPressed.connect(self.searchButtonClicked)
- 第三是各小控件功能与代码实现,其中也对应上面信号槽绑定下的各个槽函数,现在我们自左至右,自上而下开始逐个理解。
- (1)查询文本框(searchEdit)
- 这里看代码有个小技巧,那就是双击关键词,再按Ctrl+F,就给整片代码中的这个词打上小方框,然后还可以点上一个、下一个。
- 这个上面searchEdit的大小 、位置、样式等容易理解,后面接着是功能实现的代码,用来给searchEdit文本实现模糊查询。
# 得到模糊查询条件 temp = self.searchEdit.text() s = '%' for i in range(0, len(temp)): s = s + temp[i] + "%" queryCondition = ("SELECT * FROM Book WHERE %s LIKE '%s' ORDER BY %s " % ( conditionChoice, s, conditionChoice))
- 这段代码抽出来,代入实例如下图。
- 数据库sql语句实现
- 系统实现
- (2)查询按钮(searchButton)
- 大小 、位置、样式、小图标(放大镜)……,这个按钮用信号槽完成搜索动作,槽函数是searchButtonClicked,同时这个槽函数还用于上面的searchEdit,不点这个按钮,输入文本回车也能实现查询。
- 槽函数searchButtonClicked里面的实现机制是,
- (3)根据书籍分数查询(condisionComboBox)
-
这里用了一个下拉列表框,原来里面用if方法实现,改成字典的了:
# 1.选定查询书籍的类型(类型字段) conditionOrCategory = self.condisionComboBox.currentText() condition = { 'BookName': "按书名查询", 'BookId': "按书号查询", 'Auth': "按作者查询", 'Category': '按分类查询', 'Publisher': '按出版社查询' } for k, v in condition.items(): if conditionOrCategory == v: conditionOrCategory = k
- 这段代码放在分页记录查询recordQuery函数里面。这个函数的作用就是动态刷新窗体底部小控件的数值,除了查询用这个函数,下面的几个按钮都要调用,注释在代码里面。
-
- (4)跳转数字框(pageEdit)
- 这是底部的当前页码框,从currentPage(当前页)中获取,而currentPage又是来自getPageCount函数的变量totalPage(总页数)。
- (5)总页数(totalPage)
- 看代码里面的注释
- (6)跳转按钮(jumpToButton)
- 根据第(4)条的pageEdit,点击此按钮跳转到相应的页面。
- (7)前一页(prevButton)
- 根据pageEdit里面的currentPage(当前页)和totalPage(总页数),判断翻页定位。
- (8)后一页(backButton)
- 根据pageEdit里面的currentPage(当前页)和totalPage(总页数),判断翻页定位。
- (1)查询文本框(searchEdit)
5.2.3 借阅书籍(borrowBookDialog.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import qdarkstyle
import time
from PyQt5.QtSql import *
class borrowBookDialog(QDialog):
borrow_book_success_signal = pyqtSignal()
def __init__(self, StudentId, parent=None):
super(borrowBookDialog, self).__init__(parent)
self.studentId = StudentId
self.setUpUI()
self.setWindowModality(Qt.WindowModal)
self.setWindowTitle("借阅书籍")
def setUpUI(self):
# 书名,书号,作者,分类,添加数量.出版社,出版日期
# 书籍分类:哲学类、社会科学类、政治类、法律类、军事类、经济类、文化类、教育类、体育类、语言文字类、艺术类、历史类、地理类、天文学类、生物学类、医学卫生类、农业类
BookCategory = ["哲学", "社会科学", "政治", "法律", "军事", "经济", "文化", "教育", "体育", "语言文字", "艺术", "历史"
, "地理", "天文学", "生物学", "医学卫生", "农业"]
self.resize(300, 400)
self.layout = QFormLayout()
self.setLayout(self.layout)
# Label控件
self.borrowStudentLabel = QLabel("借 阅 人:")
self.borrowStudentIdLabel = QLabel(self.studentId)
self.titlelabel = QLabel(" 借阅书籍")
self.bookNameLabel = QLabel("书 名:")
self.bookIdLabel = QLabel("书 号:")
self.authNameLabel = QLabel("作 者:")
self.categoryLabel = QLabel("分 类:")
self.publisherLabel = QLabel("出 版 社:")
self.publishDateLabel = QLabel("出版日期:")
# button控件
self.borrowBookButton = QPushButton("确认借阅")
# lineEdit控件
self.bookNameEdit = QLineEdit()
self.bookIdEdit = QLineEdit()
self.authNameEdit = QLineEdit()
self.categoryComboBox = QComboBox()
self.categoryComboBox.addItems(BookCategory)
self.publisherEdit = QLineEdit()
self.publishTime = QLineEdit()
self.bookNameEdit.setMaxLength(10)
self.bookIdEdit.setMaxLength(6)
self.authNameEdit.setMaxLength(10)
self.publisherEdit.setMaxLength(10)
# 添加进formlayout
self.layout.addRow("", self.titlelabel)
self.layout.addRow(self.borrowStudentLabel, self.borrowStudentIdLabel)
self.layout.addRow(self.bookNameLabel, self.bookNameEdit)
self.layout.addRow(self.bookIdLabel, self.bookIdEdit)
self.layout.addRow(self.authNameLabel, self.authNameEdit)
self.layout.addRow(self.categoryLabel, self.categoryComboBox)
self.layout.addRow(self.publisherLabel, self.publisherEdit)
self.layout.addRow(self.publishDateLabel, self.publishTime)
self.layout.addRow("", self.borrowBookButton)
# 设置字体
font = QFont()
font.setPixelSize(20)
self.titlelabel.setFont(font)
font.setPixelSize(16)
self.borrowStudentIdLabel.setFont(font)
font.setPixelSize(14)
self.borrowStudentLabel.setFont(font)
self.bookNameLabel.setFont(font)
self.bookIdLabel.setFont(font)
self.authNameLabel.setFont(font)
self.categoryLabel.setFont(font)
self.publisherLabel.setFont(font)
self.publishDateLabel.setFont(font)
self.bookNameEdit.setFont(font)
self.bookNameEdit.setReadOnly(True)
self.bookNameEdit.setStyleSheet("background-color:#363636")
self.bookIdEdit.setFont(font)
self.authNameEdit.setFont(font)
self.authNameEdit.setReadOnly(True)
self.authNameEdit.setStyleSheet("background-color:#363636")
self.publisherEdit.setFont(font)
self.publisherEdit.setReadOnly(True)
self.publisherEdit.setStyleSheet("background-color:#363636")
self.publishTime.setFont(font)
self.publishTime.setStyleSheet("background-color:#363636")
self.categoryComboBox.setFont(font)
self.categoryComboBox.setStyleSheet("background-color:#363636")
# button设置
font.setPixelSize(16)
self.borrowBookButton.setFont(font)
self.borrowBookButton.setFixedHeight(32)
self.borrowBookButton.setFixedWidth(140)
# 设置间距
self.titlelabel.setMargin(8)
self.layout.setVerticalSpacing(10)
self.borrowBookButton.clicked.connect(self.borrowButtonClicked)
self.bookIdEdit.textChanged.connect(self.bookIdEditChanged)
self.bookIdEdit.returnPressed.connect(self.borrowButtonClicked)
def borrowButtonClicked(self):
# 获取书号,书号为空或不存在库中,则弹出错误
# 向Book_User表插入记录,更新User表以及Book表
BookId = self.bookIdEdit.text()
# BookId为空的处理
if BookId == "":
print(QMessageBox.warning(self, "警告", "你所要借的书不存在,请查看输入", QMessageBox.Yes, QMessageBox.Yes))
return
# 打开数据库
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName('./db/LibraryManagement.db')
db.open()
query = QSqlQuery()
# 如果BookId不存在
sql = "SELECT * FROM Book WHERE BookId='%s'" % BookId
query.exec_(sql)
if not query.next():
print(QMessageBox.warning(self, "警告", "你所要借的书不存在,请查看输入", QMessageBox.Yes, QMessageBox.Yes))
return
# 借书上限5本
sql = "SELECT COUNT(StudentId) FROM User_Book WHERE StudentId='%s' AND BorrowState=1" % (
self.studentId)
query.exec_(sql)
if (query.next()):
borrowNum = query.value(0)
if (borrowNum == 5):
QMessageBox.warning(self, "警告", "您借阅的书达到上限(5本),借书失败!", QMessageBox.Yes, QMessageBox.Yes)
return
# 不允许重复借书
sql = "SELECT COUNT(StudentId) FROM User_Book WHERE StudentId='%s' AND BookId='%s' AND BorrowState=1" % (
self.studentId, BookId)
query.exec_(sql)
if (query.next() and query.value(0)):
QMessageBox.warning(self, "警告", "您已经借阅了本书并尚未归还,借阅失败!", QMessageBox.Yes, QMessageBox.Yes)
return
# 更新User表
sql = "UPDATE User SET TimesBorrowed=TimesBorrowed+1,NumBorrowed=NumBorrowed+1 WHERE StudentId='%s'" % self.studentId
query.exec_(sql)
db.commit()
# 更新Book表
sql = "UPDATE Book SET NumCanBorrow=NumCanBorrow-1,NumBorrowed=NumBorrowed+1 WHERE BookId='%s'" % BookId
query.exec_(sql)
db.commit()
# 插入User_Book表
timenow = time.strftime('%Y-%m-%d', time.localtime(time.time()))
sql = "INSERT INTO User_Book VALUES ('%s','%s','%s',NULL,1)" % (self.studentId, BookId, timenow)
print(sql)
query.exec_(sql)
db.commit()
print(QMessageBox.information(self, "提示", "借阅成功!", QMessageBox.Yes, QMessageBox.Yes))
self.borrow_book_success_signal.emit()
self.close()
return
def bookIdEditChanged(self):
bookId = self.bookIdEdit.text()
if bookId == "":
self.bookNameEdit.clear()
self.publisherEdit.clear()
self.authNameEdit.clear()
self.publishTime.clear()
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName('./db/LibraryManagement.db')
db.open()
query = QSqlQuery()
sql = "SELECT * FROM Book WHERE BookId='%s'" % (bookId)
query.exec_(sql)
# 查询对应书号,如果存在就更新form
if (query.next()):
self.bookNameEdit.setText(query.value(0))
self.authNameEdit.setText(query.value(2))
self.categoryComboBox.setCurrentText(query.value(3))
self.publisherEdit.setText(query.value(4))
self.publishTime.setText(query.value(5))
return
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
mainWindow = borrowBookDialog("PB15000135")
mainWindow.show()
sys.exit(app.exec_())
- 代码分析
- 首先,这个对话框布局很简单。除了8个Label和5个LineEdit就是1个下拉列表框加最底下1个按钮。这些小控件自上而下,分两列放置到表单布局器QFormLayout。字体、样式、位置、大小、间距都设定好后,放入布局。最后再绑定3个信号槽函数,一个按钮绑定按钮单击方法、书籍ID文本框绑定两个槽,信号是文字改变bookIdEditChanged和回车及焦点离开都如同触发按钮borrowButtonClicked。太啰嗦,画图吧。
- 然后,再解释两个槽函数。borrowButtonClicked定义书籍ID不为空的时候,加上if条件语句,再应用数据库sql查询语句,一旦借阅的书籍存在,点击“确认借阅”,再应用数据库update更新用户表User和书籍表Book的信息(还设定了用户最多借阅5本的限制条件)。bookIdEditChanged的作用就是通过书籍ID的文本框是否有信息、信息是否正确,同时触发其它控件里的信息,然后用回车、点击按钮等方法作出上面borrowButtonClicked函数相同的效果。
5.2.4 借阅状态(BorrowStatusViewer.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *
import qdarkstyle
import time
from PyQt5.QtSql import *
class returnBookDialog(QDialog):
return_book_success_signal=pyqtSignal()
def __init__(self, StudentId, parent=None):
super(returnBookDialog, self).__init__(parent)
self.studentId = StudentId
self.setUpUI()
self.setWindowModality(Qt.WindowModal)
self.setWindowTitle("归还书籍")
def setUpUI(self):
# 书名,书号,作者,分类,添加数量.出版社,出版日期
# 书籍分类:哲学类、社会科学类、政治类、法律类、军事类、经济类、文化类、教育类、体育类、语言文字类、艺术类、历史类、地理类、天文学类、生物学类、医学卫生类、农业类
BookCategory = ["哲学", "社会科学", "政治", "法律", "军事", "经济", "文化", "教育", "体育", "语言文字", "艺术", "历史"
, "地理", "天文学", "生物学", "医学卫生", "农业"]
self.resize(300, 400)
self.layout = QFormLayout()
self.setLayout(self.layout)
# Label控件
self.returnStudentLabel = QLabel("还 书 人:")
self.returnStudentIdLabel = QLabel(self.studentId)
self.titlelabel = QLabel(" 归还书籍")
self.bookNameLabel = QLabel("书 名:")
self.bookIdLabel = QLabel("书 号:")
self.authNameLabel = QLabel("作 者:")
self.categoryLabel = QLabel("分 类:")
self.publisherLabel = QLabel("出 版 社:")
self.publishDateLabel = QLabel("出版日期:")
# button控件
self.returnBookButton = QPushButton("确认归还")
# lineEdit控件
self.bookNameEdit = QLineEdit()
self.bookIdEdit = QLineEdit()
self.authNameEdit = QLineEdit()
self.categoryComboBox = QComboBox()
self.categoryComboBox.addItems(BookCategory)
self.publisherEdit = QLineEdit()
self.publishTime = QLineEdit()
self.bookNameEdit.setMaxLength(10)
self.bookIdEdit.setMaxLength(6)
self.authNameEdit.setMaxLength(10)
self.publisherEdit.setMaxLength(10)
# 添加进formlayout
self.layout.addRow("", self.titlelabel)
self.layout.addRow(self.returnStudentLabel, self.returnStudentIdLabel)
self.layout.addRow(self.bookNameLabel, self.bookNameEdit)
self.layout.addRow(self.bookIdLabel, self.bookIdEdit)
self.layout.addRow(self.authNameLabel, self.authNameEdit)
self.layout.addRow(self.categoryLabel, self.categoryComboBox)
self.layout.addRow(self.publisherLabel, self.publisherEdit)
self.layout.addRow(self.publishDateLabel, self.publishTime)
self.layout.addRow("", self.returnBookButton)
# 设置字体
font = QFont()
font.setPixelSize(20)
self.titlelabel.setFont(font)
font.setPixelSize(16)
self.returnStudentIdLabel.setFont(font)
font.setPixelSize(14)
self.returnStudentLabel.setFont(font)
self.bookNameLabel.setFont(font)
self.bookIdLabel.setFont(font)
self.authNameLabel.setFont(font)
self.categoryLabel.setFont(font)
self.publisherLabel.setFont(font)
self.publishDateLabel.setFont(font)
self.bookNameEdit.setFont(font)
self.bookNameEdit.setReadOnly(True)
self.bookNameEdit.setStyleSheet("background-color:#363636")
self.bookIdEdit.setFont(font)
self.authNameEdit.setFont(font)
self.authNameEdit.setReadOnly(True)
self.authNameEdit.setStyleSheet("background-color:#363636")
self.publisherEdit.setFont(font)
self.publisherEdit.setReadOnly(True)
self.publisherEdit.setStyleSheet("background-color:#363636")
self.publishTime.setFont(font)
self.publishTime.setStyleSheet("background-color:#363636")
self.categoryComboBox.setFont(font)
self.categoryComboBox.setStyleSheet("background-color:#363636")
# button设置
font.setPixelSize(16)
self.returnBookButton.setFont(font)
self.returnBookButton.setFixedHeight(32)
self.returnBookButton.setFixedWidth(140)
# 设置间距
self.titlelabel.setMargin(8)
self.layout.setVerticalSpacing(10)
self.returnBookButton.clicked.connect(self.returnButtonClicked)
self.bookIdEdit.textChanged.connect(self.bookIdEditChanged)
def returnButtonClicked(self):
# 获取书号,书号为空或并未借阅,则弹出错误
# 更新Book_User表User表以及Book表
BookId = self.bookIdEdit.text()
# BookId为空的处理
if (BookId == ""):
print(QMessageBox.warning(self, "警告", "你所要还的书不存在,请查看输入", QMessageBox.Yes, QMessageBox.Yes))
return
# 打开数据库
db = db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName('./db/LibraryManagement.db')
db.open()
query = QSqlQuery()
# 如果未借阅
sql = "SELECT * FROM User_Book WHERE StudentId='%s' AND BookId='%s' AND BorrowState=1" %(self.studentId,BookId)
query.exec_(sql)
if (not query.next()):
print(QMessageBox.information(self, "提示", "您并未借阅此书,故无需归还", QMessageBox.Yes, QMessageBox.Yes))
return
# 更新User表
sql = "UPDATE User SET NumBorrowed=NumBorrowed-1 WHERE StudentId='%s'" % self.studentId
query.exec_(sql)
db.commit()
# 更新Book表
sql = "UPDATE Book SET NumCanBorrow=NumCanBorrow+1 WHERE BookId='%s'" % BookId
query.exec_(sql)
db.commit()
# 更新User_Book表
timenow = time.strftime('%Y-%m-%d', time.localtime(time.time()))
sql = "UPDATE User_Book SET ReturnTime='%s',BorrowState=0 WHERE StudentId='%s' AND BookId='%s' AND BorrowState=1" % (timenow,self.studentId,BookId)
query.exec_(sql)
db.commit()
print(QMessageBox.information(self, "提示", "归还成功!", QMessageBox.Yes, QMessageBox.Yes))
self.return_book_success_signal.emit()
self.close()
return
def bookIdEditChanged(self):
bookId = self.bookIdEdit.text()
if (bookId == ""):
self.bookNameEdit.clear()
self.publisherEdit.clear()
self.authNameEdit.clear()
self.publishTime.clear()
db = QSqlDatabase.addDatabase("QSQLITE")
db.setDatabaseName('./db/LibraryManagement.db')
db.open()
query = QSqlQuery()
# 在User_Book表中找借阅记录,如果存在借阅,则更新form内容
sql = "SELECT * FROM User_Book WHERE StudentId='%s' AND BookId='%s' AND BorrowState=1" % (
self.studentId, bookId)
query.exec_(sql)
if (query.next()):
# 更新form内容
sql = "SELECT * FROM Book WHERE BookId='%s'" % (bookId)
query.exec_(sql)
# 查询对应书号,如果存在就更新form
if (query.next()):
self.bookNameEdit.setText(query.value(0))
self.authNameEdit.setText(query.value(2))
self.categoryComboBox.setCurrentText(query.value(3))
self.publisherEdit.setText(query.value(4))
self.publishTime.setText(query.value(5))
return
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
mainMindow = returnBookDialog("PB15000135")
mainMindow.show()
sys.exit(app.exec_())
- 代码分析
- 这个对话框和借阅书籍的对话框总体一样。包括布局和槽函数,大同小异。只是归还的槽函数中,更改了归还的书籍是否存在,是否借阅过,也是在if语句的条件判断中。
5.2.5 归还书籍(returnBookDialog.py)
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import Qt
import qdarkstyle
from PyQt5.QtSql import *
class BorrowStatusViewer(QWidget):
def __init__(self, studentId):
super(BorrowStatusViewer, self).__init__()
self.resize(700, 500)
self.studentId = studentId
self.setWindowTitle("欢迎使用图书馆管理系统")
self.setUpUI()
def setUpUI(self):
self.db = QSqlDatabase.addDatabase("QSQLITE")
self.db.setDatabaseName('./db/LibraryManagement.db')
self.db.open()
# 分为两块,上方是已借未归还书,下方是已归还书
self.layout = QVBoxLayout(self)
# Label设置
self.borrowedLabel = QLabel("未归还:")
self.returnedLabel = QLabel("已归还:")
self.borrowedLabel.setFixedHeight(32)
self.borrowedLabel.setFixedWidth(60)
self.returnedLabel.setFixedHeight(32)
self.returnedLabel.setFixedWidth(60)
font = QFont()
font.setPixelSize(18)
self.borrowedLabel.setFont(font)
self.returnedLabel.setFont(font)
# Table和Model
self.borrowedTableView = QTableView()
self.borrowedTableView.horizontalHeader().setStretchLastSection(True)
self.borrowedTableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.borrowedTableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.returnedTableView = QTableView()
self.returnedTableView.horizontalHeader().setStretchLastSection(True)
self.returnedTableView.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.returnedTableView.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.borrowedQueryModel = QSqlQueryModel()
self.returnedQueryModel = QSqlQueryModel()
self.borrowedTableView.setModel(self.borrowedQueryModel)
self.returnedTableView.setModel(self.returnedQueryModel)
self.borrowedQuery()
self.borrowedQueryModel.setHeaderData(0, Qt.Horizontal, "书名")
self.borrowedQueryModel.setHeaderData(1, Qt.Horizontal, "书号")
self.borrowedQueryModel.setHeaderData(2, Qt.Horizontal, "作者")
self.borrowedQueryModel.setHeaderData(3, Qt.Horizontal, "分类")
self.borrowedQueryModel.setHeaderData(4, Qt.Horizontal, "出版社")
self.borrowedQueryModel.setHeaderData(5, Qt.Horizontal, "出版时间")
self.borrowedQueryModel.setHeaderData(6, Qt.Horizontal, "借出时间")
self.returnedQuery()
self.returnedQueryModel.setHeaderData(0, Qt.Horizontal, "书名")
self.returnedQueryModel.setHeaderData(1, Qt.Horizontal, "书号")
self.returnedQueryModel.setHeaderData(2, Qt.Horizontal, "作者")
self.returnedQueryModel.setHeaderData(3, Qt.Horizontal, "分类")
self.returnedQueryModel.setHeaderData(4, Qt.Horizontal, "出版社")
self.returnedQueryModel.setHeaderData(5, Qt.Horizontal, "出版时间")
self.returnedQueryModel.setHeaderData(6, Qt.Horizontal, "借阅时间")
self.returnedQueryModel.setHeaderData(7, Qt.Horizontal, "归还时间")
self.layout.addWidget(self.borrowedLabel)
self.layout.addWidget(self.borrowedTableView)
self.layout.addWidget(self.returnedLabel)
self.layout.addWidget(self.returnedTableView)
return
def borrowedQuery(self):
sql = "SELECT Book.BookName,Book.BookId,Auth,Category,Publisher,PublishTime,BorrowTime FROM Book,User_Book " \
"WHERE Book.BookId=User_Book.BookId AND User_Book.BorrowState=1 AND StudentId='%s'" % self.studentId
self.borrowedQueryModel.setQuery(sql)
return
def returnedQuery(self):
sql = "SELECT Book.BookName,Book.BookId,Auth,Category,Publisher,PublishTime,BorrowTime,ReturnTime FROM Book," \
"User_Book WHERE Book.BookId=User_Book.BookId AND User_Book.BorrowState=0 AND StudentId='%s'" % \
self.studentId
self.returnedQueryModel.setQuery(sql)
return
if __name__ == "__main__":
app = QApplication(sys.argv)
app.setWindowIcon(QIcon("./images/MainWindow_1.png"))
app.setStyleSheet(qdarkstyle.load_stylesheet_pyqt5())
mainMindow = BorrowStatusViewer("PB15000135")
mainMindow.show()
sys.exit(app.exec_())
- 代码分析
- 这个页面展示了当前用户借阅图书的情况。分为两块,上方是已借未归还书,下方是已归还书。用了一个垂直布局,然后上下分别放置了两个QTableView视图表。
- 数据库sql语句用了SELECT,然后未还的搜索User和User_Book两个表,WHERE语句是根据图书ID、借阅状态BorrowState=1和当前执行搜索的学生ID。
- 已归还的图书视图,也用了SELECT,然后搜索User和User_Book两个表,WHERE语句是根据图书ID、借阅状态BorrowState=0和当前执行搜索的学生ID。
- 这个页面没有信号槽函数,不过学习了数据库搜索视图,放置到QTableView中。