大家好,这里是Seon塞翁。笔者在最近的工作中做了一个基于PyQt5实现GUI的数据处理工具,领导表示“我想一双击就能直接看到情况啊,不要打开后还要我自己输入这个点击那个的!”好吧,既然上头有需求,打工人就得照办。想想以前用过的许多桌面软件,启动时都会有个欢迎画面,同时后台预加载一些内容。那么应该要怎么实现呢?先看看效果吧。
1、界面设计
首先欢迎画面要有一个好看的背景,还有进度条和进度提示信息,那么先用一个 Widget
来做容器,再把用于显示 Logo 和进度信息的 label
拖出来,最后摆上进度条 progressBar
。
然后是启动加载完成后显示的主页,用一个 lineEdit
显示接收到的预处理结果。
此时启动画面还是一个默认风格的窗体,让我们美化一下样式,让它看起来更像样。
class LoadWin(QWidget, loadwin.Ui_Form): # 启动画面类 -----------
def __init__(self):
super(LoadWin, self).__init__()
self.setupUi(self)
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框
self.setStyleSheet("#Form{background-color:'#4682B4'}"
"#label_info{background-color:'#4682B4';color:white;font-weight:600;}"
) # 设置启动窗背景色和进度信息的字体样式等
pix = QPixmap("./load_logo.png") # 加载logo
self.label_logo.setPixmap(pix)
self.label_logo.setScaledContents(True) # 图像拉伸填充
然后是启动计算完成后要显示的主页,定义一个函数接收计算结果。
class MainWin(QWidget, mainwin.Ui_Form): # 主页界面类 -----------
def __init__(self):
super(MainWin, self).__init__()
self.setupUi(self)
def set_data(self, mes): # 接收进度线程的计算结果
self.lineEdit.setText(mes)
2、进度条逻辑
继续完善启动画面类 class LoadWin
,在 __init__
方法中添加代码,通过定时器来为进度条增值,完成初始化后准备启动计算线程。
self.timer = QBasicTimer() # 定时器对象
self.main_win = MainWin() # 进度结束后要显示的主页
self.step = 0 # 进度值
self.proess_run()
实例化线程,分别绑定线程类中的进度环节信号和结束时回传数据的信号。
def proess_run(self): # 启动进度线程
self.cal = LoadThread() # 线程对象
self.cal.part_signal.connect(self.process_set_part)
self.cal.data_signal.connect(self.show_main_win)
self.cal.start() # 调用线程run
根据线程回传的进度环节,启动定时器,分步为进度条调整增值速度和增量,设计为完成一个环节后就从头开始增值,即进度条多次重新充满。一般预处理环节不应过多,每个环节执行时间也不宜过长。如下仅设两个环节,用回传的 0 和 1 来识别到了哪一步,而进度条从 0 或 1 开始增值在视觉上也并无太大区别。当然也可根据需要把进度值 0~100 分为多个环节,即进度条总共仅充满一次。
def process_set_part(self, num):
self.step = num # 进度从num开始
self.progressBar.setValue(self.step)
if num == 0:
self.timer.start(20, self) # 启动QBasicTimer, 每20毫秒调用一次回调函数
self.label_info.setText("正在计算数据...")
if num == 1:
self.timer.stop() # 重启,调整进度条增值速度
self.timer.start(10, self)
self.label_info.setText("已完成计算,等待主页加载...")
重写定时器回调函数,为进度条增值。
def timerEvent(self, *args, **kwargs): # QBasicTimer的事件回调函数
self.progressBar.setValue(self.step) # 设置进度条的值
if self.step < 100:
self.step += 1
完成计算后将结果传给主页,显示。
def show_main_win(self, mes):
self.main_win.set_data(mes)
self.main_win.show()
self.close()
3、计算线程类
经过以上操作,基础准备才算做好了,下面继续实现真正用于执行任务的部分。run
方法被调用时发射信号,告诉启动界面我要开始第一步啦!完成第一步后再说一声,如此递进到最后回传计算结果。
class LoadThread(QThread): # 自定义计算线程类 -----------
part_signal = pyqtSignal(int) # 进度环节信号
data_signal = pyqtSignal(str) # 数据传递信号
def __init__(self):
super().__init__()
def run(self):
self.part_signal.emit(0)
self.fun_part_one()
self.part_signal.emit(1)
sleep(1) # 模拟加载耗时
self.data_signal.emit("计算结果:2021")
def fun_part_one(self):
sleep(3) # 模拟计算耗时
4、回顾流程及源码
一图流回顾执行流程:
附完整代码如下:
from PyQt5.QtWidgets import QWidget, QApplication
from PyQt5.QtGui import QPixmap
from PyQt5.QtCore import Qt, pyqtSignal, QThread, QBasicTimer
import sys
from time import sleep
from myqt import loadwin, mainwin
class LoadWin(QWidget, loadwin.Ui_Form): # 启动画面类 -----------
def __init__(self):
super(LoadWin, self).__init__()
self.setupUi(self)
self.setWindowFlags(Qt.FramelessWindowHint) # 无边框
self.setStyleSheet("#Form{background-color:'#4682B4'}"
"#label_info{background-color:'#4682B4';color:white;font-weight:600;}"
) # 设置启动窗背景色和进度信息的字体样式等
pix = QPixmap("./load_logo.png") # 加载logo
self.label_logo.setPixmap(pix)
self.label_logo.setScaledContents(True) # 图像拉伸填充
self.timer = QBasicTimer() # 定时器对象
self.main_win = MainWin() # 进度结束后要显示的主页
self.step = 0 # 进度值
self.proess_run()
def proess_run(self): # 启动进度线程
self.cal = LoadThread() # 线程对象
self.cal.part_signal.connect(self.process_set_part)
self.cal.data_signal.connect(self.show_main_win)
self.cal.start() # 调用线程run
def process_set_part(self, num):
self.step = num # 进度从num开始
self.progressBar.setValue(self.step)
if num == 0:
self.timer.start(20, self) # 启动QBasicTimer, 每20毫秒调用一次回调函数
self.label_info.setText("正在计算数据...")
if num == 1:
self.timer.stop() # 重启,调整进度条增值速度
self.timer.start(10, self)
self.label_info.setText("已完成计算,等待主页加载...")
def timerEvent(self, *args, **kwargs): # QBasicTimer的事件回调函数
self.progressBar.setValue(self.step) # 设置进度条的值
if self.step < 100:
self.step += 1
def show_main_win(self, mes):
self.main_win.set_data(mes)
self.main_win.show()
self.close()
class LoadThread(QThread): # 自定义计算线程类 -----------
part_signal = pyqtSignal(int) # 进度环节信号
data_signal = pyqtSignal(str) # 数据传递信号
def __init__(self):
super().__init__()
def run(self):
self.part_signal.emit(0)
self.fun_part_one()
self.part_signal.emit(1)
sleep(1) # 模拟加载耗时
self.data_signal.emit("计算结果:2021")
def fun_part_one(self):
sleep(3) # 模拟计算耗时
class MainWin(QWidget, mainwin.Ui_Form): # 主页界面类 -----------
def __init__(self):
super(MainWin, self).__init__()
self.setupUi(self)
def set_data(self, mes): # 接收进度线程的计算结果
self.lineEdit.setText(mes)
if __name__ == '__main__':
app = QApplication(sys.argv)
w = LoadWin()
w.show()
sys.exit(app.exec())
另外,笔者入坑PyQt5时写的第一篇文章中也提到了启动画面,是个简易版的仅显示欢迎画面而未有耗时预处理计算的例子,有兴趣可以点击 启动画面与窗口间跳转的实现 看一看哈哈哈。
感谢阅读!