武警广西总队,广西 南宁 532000
摘要:交叉检查中的检查对象抽签,要求不检查自己、不相互检查,该文阐述了基于PyQt5开发的交叉检查抽签软件,实现了交叉检查抽签中的特殊要求,提高了抽签的效率。
关键词:PyQt5;交叉检查;抽签
Python是一种语法简洁、功能强大的编程语言,它的应用范围很广,而GUI图形用户界面开发则是Python的一个非常重要的方向之一,PyQt5作为一个跨平台、简单易用、高效的GUI框架,将Python与Qt融为一体,PyQt5允许使用Python语言调用Qt库中的API,在保留了Qt高效率运行的同时,大大提高了开发效率[1]。本文基于PyQt5设计开发了一款抽签软件,主要用于各单位进行交叉检查抽签,具有一定的实用价值。
1.系统分析
软件主要用于各单位之间进行交叉检查抽签,为公平起见,设置两次抽签,即首先按照序列由各单位依次抽取抽签的顺序,然后再按抽签顺序依次抽取交叉检查的对象。其中有两个条件需要遵守:一是不能抽到自己本单位;二是不能抽到检查本单位的单位,防止相互检查。抽签之前,先按顺序录入参与抽签的单位。然后由各单位依次操作或由工作人员代替操作按钮“开始”和“停止”完成抽签,抽签过程中,屏幕随机滚动显示待抽签的内容,按下“停止”按钮后屏幕上显示的内容即为该单位所抽中内容。抽签完成后,可将抽签结果导出为文件。抽签主要流程如图1所示。
图1 抽签流程
2.系统实现
2.1 开发环境安装
本文使用的系统环境为Windows 7 64位,在已安装Python的基础上,在项目文件夹下使用命令创建虚拟环境:python -m venv venv。激活虚拟环境后,分别使用pip install PyQt5、pip install PyQt5-tools、pip install PyQt5designer命令安装相关Python库。
2.2软件GUI界面制作
QtDesigner是Qt提供的一个GUI辅助设计工具,它在很大程度上减轻了设计用户界面时的工作量,使Qt程序员能仅用鼠标拖动和编写少量代码就能够完成大部分用户界面的制作[2]。在虚拟环境目录venv下的Lib\site-packages\QtDesigner文件夹中,点击运行designer.exe即可进行GUI界面制作。界面设计如图2所示。其中左侧列表用于显示当前抽签的单位及抽签结果,中间“单位X”为抽签过程中滚动显示的抽签对象,下方分别为“开始”、“停止”、“导出”三个按键。
图2 软件界面设计
先使用QtDesigner设计制作出软件界面的整体框架,得到draw.ui文件,然后使用命令将.ui文件转换为.py文件:pyuic5 -o draw.py draw.ui,转换后生成的代码如下:
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1225, 910)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.startButton = QtWidgets.QPushButton(self.centralwidget)
self.startButton.setGeometry(QtCore.QRect(680, 620, 131, 51))
font = QtGui.QFont()
font.setFamily("隶书")
font.setPointSize(20)
self.startButton.setFont(font)
self.startButton.setObjectName("startButton")
……
self.label = QtWidgets.QLabel(self.centralwidget)
self.label.setGeometry(QtCore.QRect(540, 340, 571, 201))
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(110)
self.label.setFont(font)
self.label.setTextFormat(QtCore.Qt.AutoText)
self.label.setAlignment(QtCore.Qt.AlignCenter)
self.label.setObjectName("label")
self.tableWidget = QtWidgets.QTableWidget(self.centralwidget)
self.tableWidget.setGeometry(QtCore.QRect(30, 260, 331, 481))
self.tableWidget.setRowCount(15)
self.tableWidget.setColumnCount(3)
self.tableWidget.setObjectName("tableWidget")
2.3抽签功能的实现
(1)导入名单。将待抽签的单位写入list.txt文件,每一行一个单位,软件启动时读取list.txt写入列表name_list中,同时根据单位的个数生成相应的序号写入列表order_list中。相关代码如下:
def setList(self):
with open('list.txt') as listfile:
lines = listfile.readlines()
self.name_list = []
for line in lines:
self.name_list.append(line.rstrip())
row = len(self.name_list)
self.tableWidget.setRowCount(row)
self.tableWidget.setGeometry(QtCore.QRect(20, 400, 380, 34*row))
self.order_list = []
for i in range(row):
x = str(i+1)
self.order_list.append(x.rjust(2,'0'))
data = QTableWidgetItem(self.name_list[i])
self.tableWidget.setItem(i,0,data)
(2)抽取抽签顺序。抽签使用random.shuffle函数随机排列列表中元素的顺序,然后取第1个元素,在界面中显示,通过新建1个Qtime对象timer的timeout信号不断调用抽签函数来实现在界面中的抽签对象滚动显示。“开始”与“停止”按钮分别控制timer的start和stop,实现开始滚动的抽签效果和停止滚动抽中结果,每抽完1 个会将使用pop函数将该结果从待抽取列表中删除。抽签顺序抽完后,将“开始”与“停止”按钮的点击信号与抽取抽签顺序的槽函数startRandomOrder、stopRandomOrder断开,与抽取检查对象的槽函数startRandomObject、stopRandomObject连接,同时将左侧列表按照抽签顺序进行排序,以进行下一步检查对象的抽取。相关代码下:
def draw(self):
if Ui_MainWindow.xuhao:
random.shuffle(self.order_list)
self.label.setText(str(self.order_list[0]))
else:
random.shuffle(self.name_list)
self.label.setText(self.name_list[0])
def startRandomOrder(self):
self.timer.start(1)
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.tableWidget.item(Ui_MainWindow.m,0).setSelected(True)
def stopRandomOrder(self):
self.timer.stop()
self.stopButton.setEnabled(False)
item = self.order_list.pop(0)
self.label.setText(item)
data = QTableWidgetItem(item)
self.tableWidget.setItem(Ui_MainWindow.m, 1, data)
if len(self.order_list)>0:
self.startButton.setEnabled(True)
self.tableWidget.item(Ui_MainWindow.m, 0).setSelected(False)
Ui_MainWindow.m = Ui_MainWindow.m + 1
self.tableWidget.item(Ui_MainWindow.m, 0).setSelected(True)
else:
self.startButton.setEnabled(True)
Ui_MainWindow.xuhao = False
self.tableWidget.item(Ui_MainWindow.m, 0).setSelected(False)
#self.timer.timeout.connect(self.chouqian)
self.startButton.clicked.connect(self.startRandomObject)
self.startButton.clicked.disconnect(self.startRandomOrder)
self.stopButton.clicked.connect(self.stopRandomObject)
self.stopButton.clicked.disconnect(self.stopRandomOrder)
self.tableWidget.verticalHeader().setVisible(False)
self.tableWidget.sortByColumn(1,QtCore.Qt.AscendingOrder)
font = QtGui.QFont()
font.setFamily("黑体")
font.setPointSize(110)
self.label.setFont(font)
(3)抽取检查对象。检查对象的抽取与抽签顺序的抽取类似,不同的地方在于要考虑不能抽中自己,也不能抽中已经抽中检查本单位的单位。在抽签开始时,首先要判断待抽取列表中是否有符合两个条件的元素,如果有,则将其取出并存入临时的tempItem中,这一轮抽取完成后再将tempItem添加回待抽取列表。相关代码如下:
def startRandomObject(self):
self.timer.start(1)
self.startButton.setEnabled(False)
self.stopButton.setEnabled(True)
self.tableWidget.item(Ui_MainWindow.n,0).setSelected(True)
currentItem = self.tableWidget.item(Ui_MainWindow.n,0).text()
if self.name_list.count(currentItem):
self.name_list.remove(currentItem)
self.tempItem = currentItem
Ui_MainWindow.flag = True
else:
x = self.result_list.index(currentItem)
self.tempItem = self.tableWidget.item(x,0).text()
if self.name_list.count(self.tempItem):
self.name_list.remove(self.tempItem)
Ui_MainWindow.flag = True
def stopRandomObject(self):
self.timer.stop()
self.stopButton.setEnabled(False)
item = self.name_list.pop(0)
self.result_list.append(item)
self.label.setText(item)
data = QTableWidgetItem(item)
#data.setTextAlignment(QtCore.Qt.AlignJustify)
self.tableWidget.setItem(Ui_MainWindow.n, 2, data)
if Ui_MainWindow.flag:
self.name_list.append(self.tempItem)
Ui_MainWindow.flag = False
if len(self.name_list)>0:
self.startButton.setEnabled(True)
self.tableWidget.item(Ui_MainWindow.n, 0).setSelected(False)
print(self.name_list)
Ui_MainWindow.n = Ui_MainWindow.n + 1
self.tableWidget.item(Ui_MainWindow.n, 0).setSelected(True)
else:
self.exportButton.setEnabled(True)
(4)抽签结果的导出。抽签完成后,点击“导出”按钮函数将抽签结果导出,生成以当前时间戳为文件名的.txt文件,并提示“导出抽签结果成功!”,其槽函数如下:
def exportResult(self):
filename = time.strftime('%Y%m%d%H%M%S抽签结果.txt')
file = open(filename,'w',encoding='utf-8')
for i in range(Ui_MainWindow.row):
result=self.tableWidget.item(i,0).text()+'-'+ self.tableWidget.item(i,1).text()+'-'+ self.tableWidget.item(i,2).text() +'\n'
file.write(result)
file.close()
from PyQt5.QtWidgets import QMessageBox
QMessageBox.information(None, "提示", "导出抽签结果成功", QMessageBox.Ok )
(5)界面的美化。为使抽签界面更加美观,可对布局的代码手动调整样式、位置等,并添加背景图:MainWindow.setStyleSheet("#MainWindow{border-image:url(bg.jpg)}"),最终界面如图3所示。
图3 软件最终界面
(6)程序打包。 为使程序能在没有安装Python的电脑上正常使用,需要将.py文件转换成.exe文件[3],使用命令:pyinstaller -F -w draw.py。将生成的draw.exe文件和背景文件bd.jpg、单位列表文件list.txt放于同一路径下,双击draw.exe即可正常运行抽签程序。
3结语
本文利用PyQt5设计制作了的交叉检查抽签软件,满足了交叉检查中不检查自己、不相互检查的特殊要求,相比手工抽签极大提高了抽签效率,保证了公平性,在多次交叉检查当中发挥了重要作用。
参考文献
[1]王小科,李艳.Python GUI设计PyQt5从入门到实践[M].长春:吉林大学出版社,2020.
[2]肖文鹏.用PyQt进行Python下的GUI开发[J].中文信息,2002(07).
[3]陶文玲,侯冬青.PyQt5与Qt设计师在GUI开发中的应用[J].湖南邮电职业技术学院学报,2020(1)