上一篇文章介绍了如何使用PyQt操作SQLite数据库,并且以“科目管理”模块为例,完成了科目列表查询、科目添加功能。这篇文章在上一篇文章的基础上将“科目管理”模块功能进行完成,将分页、条件查询、编辑、删除、数据校验功能添加到该模块中,使之构成一个完整的功能模块。代码已经上传到Gitee上(courseScheduling: 使用PyQT5开发桌面应用教务排课软件),可进行更新查看。
数据校验
数据校验这里是比较简单的,在科目对话框中,对科目名称进行空的判断和科目名称是否重复的判断,因为添加的科目名称不能为空,并且不能重复。该代码是在原有的科目对话框代码中添加的(src/module/subject/SubjectDialog.py),具体的校验方法如下:
# 校验输入内容合法性
def __validate(self):
subjectName = self.subjectName.text().strip()
if subjectName == "":
QMessageBox.critical(self, "输入错误", "科目名称不能为空!", QMessageBox.Ok)
return False
db = DbUtil.getDb()
# 数据库查询对象
query = QSqlQuery()
query.prepare("select count(*) from subject where name=:name")
query.bindValue(":name", subjectName)
query.exec_()
if query.next():
count = int(query.value(0))
if count > 0:
QMessageBox.critical(self, "输入错误", "科目名称不能重复!", QMessageBox.Ok)
return False
return True
分页查询
分页是查询的基本功能之一,基本上只要涉及列表数据的查询,基本上都需要分页功能。因为各个模块都会使用到分页,所以将分页代码进行了封装,封装成 Page 类(src/module/util/Page.py),具体代码示例如下:
# 分页
from PyQt5.QtWidgets import QPushButton, QLineEdit
class Page():
'''
prevBtn:上一页按钮\n
nextBtn:下一页按钮\n
pageLineEdit:转到页输入框
'''
def __init__(self, prevBtn:QPushButton, nextBtn:QPushButton, pageLineEdit:QLineEdit) -> None:
self.__prevBtn = prevBtn
self.__nextBtn = nextBtn
self.__pageLineEdit = pageLineEdit
# 当前页码
self.__currentPage = 1
# 总页数
self.__totalPage = 1
# 数据总量
self.__totalCount = 0
# 每页数据数量
self.__pageSize = 10
self.__update()
@property
def currentPage(self):
return self.__currentPage
@currentPage.setter
def currentPage(self, vaule):
if vaule <= self.__totalPage:
self.__currentPage = vaule
self.__update()
@property
def totalPage(self) -> int:
return self.__totalPage
@property
def totalCount(self) -> int:
return self.__totalCount
@totalCount.setter
def totalCount(self, value):
self.__totalCount = value
# 设置总页数
self.__totalPage = int((self.__totalCount + self.__pageSize - 1) / self.__pageSize)
self.__update()
@property
def pageSize(self) -> int:
return self.__pageSize
@pageSize.setter
def pageSize(self, value):
self.__pageSize = value
# 下一页方法
def next(self):
self.currentPage += 1
if self.currentPage > self.totalPage:
self.currentPage = self.totalPage
self.__update()
# 上一页方法
def prev(self):
self.currentPage -= 1
if self.currentPage < 1:
self.currentPage = 1
self.__update()
# 获取分页起始索引方法
def pageIndex(self) -> int:
return (self.currentPage - 1) * self.pageSize
# 根据页码更新分页按钮和页码输入框内容
def __update(self):
self.__prevBtn.setEnabled(True)
self.__nextBtn.setEnabled(True)
# 首页,上一页按钮不可用
if self.currentPage == 1:
self.__prevBtn.setEnabled(False)
# 末页,下一页按钮不可用
if self.currentPage == self.totalPage:
self.__nextBtn.setEnabled(False)
# 更新页码输入框内容:当前页
self.__pageLineEdit.setText("%d / %d" % (self.currentPage, self.totalPage))
这里需要说明的是,在创建Page对象实例的时候,传进了3个对象,分别是“上一页”按钮,“下一页”按钮,“转到页”输入框,放入这3个对象的作用是在进行上一页、下一页操作时,动态判断按钮是否可用和转到页输入框中的显示内容,这样就将窗口分页显示的控件进行了集中管理,方便使用。
接下来的使用就比较方便了,在需要进行分页的地方声明Page对象实例,根据查询需求放入对应的参数就可以了。
SQLite的分页语句:
select 字段1,字段2,... from 数据库表 limit 起始索引(从0开始), 数量
具体的分页实现代码就不在文章中显示了,因为分页的逻辑代码各种编程语言都差不多,具体的代码在 src/module/subject/SubjectWidget.py 中的 list 方法。
数据记录操作
针对每行的科目数据的操作有3个,分别是:查看科目详情、编辑科目、删除科目,这个和Web中的应用都是一样的,不同的是如何在PyQt的表格中添加这三种操作的按钮。
# 设置查看详情、编辑、删除按钮
btnBox = QGroupBox()
hLayout = QHBoxLayout()
# 查看详情按钮
detailBtn = QPushButton("查看")
detailBtn.setFixedHeight(30)
detailBtn.setProperty("subjectName", subjectName)
detailBtn.setProperty("desc", desc)
# 编辑按钮
editBtn = QPushButton("编辑")
editBtn.setFixedHeight(30)
editBtn.setProperty("id", id)
editBtn.setProperty("subjectName", subjectName)
editBtn.setProperty("desc", desc)
# 删除按钮
delBtn = QPushButton("删除")
delBtn.setFixedHeight(30)
delBtn.setProperty("id", id)
# 加入布局
hLayout.addWidget(detailBtn)
hLayout.addWidget(editBtn)
hLayout.addWidget(delBtn)
btnBox.setLayout(hLayout)
self.subjectDataTable.setCellWidget(curRow, 3, btnBox)
# 连接按钮槽函数
detailBtn.clicked.connect(self.detailSubject)
editBtn.clicked.connect(self.editSubject)
delBtn.clicked.connect(self.deleteSubject)
这里的代码比较长,原因是按钮添加到表格中,采用的是编码方式,所以代码量就比较大了,如果你有更好的方式,麻烦请你告诉我,谢谢。
首先创建QGroupBox容器,设置该容器的布局为QHBoxLayout水平布局,然后在该水平布局中加入查看、编辑、删除3个操作按钮,完成后,调用 QTableWidget.setCellWidget(行号, 列号, 容器) 将这3个按钮所在的容器放入指定的单元格。注意:行号、列号从0开始。完成后,对这3个按钮进行对应的槽函数连接就可以了。
需要说明的一点就是 setProperty(属性名, 属性值) 方法,对按钮设置属性的原因是为了让槽函数可以根据按钮的属性获取需要的数据。比如下面所展示的查看科目详情的方法代码。
# 查看科目详情槽函数
def detailSubject(self):
# 获取信号发出者对象
sender = self.sender()
name = sender.property("subjectName")
desc = sender.property("desc")
SubjectDetailDialog(self, name, desc).show()
sender() 方法可以获取信号发射对象,然后通过 property(属性名) 方法获取需要的属性值,再进行后续操作。
至于编辑、删除代码就不再进行说明了,这都是比较常见的内容,有兴趣的读者,可以通过更新代码进行查看。
至此,“科目管理”功能模块的代码可以算是完成了,教务排课软件需要用到的知识点也基本上介绍完了。其它的模块开发也和“科目管理”模块一样,有兴趣的读者可以按照自己的想法来完成其它模块。
公众号