pyqt5耗时线程阻塞界面
程序员文章站
2022-07-02 09:13:53
参考网址1:https://blog.csdn.net/xyisv/article/details/88292870参考网址2:https://ask.csdn.net/questions/8118741.问题及原因描述:在使用pyqt5编写UI的时候,正如参考网址1所述,我们一般会将后台任务与界面区分,但我自己在实现的时候发现即使使用后台线程,但仍然会阻塞界面的操作,类似问题在参考网址2中也有提到。通过对比我自己的代码和参考网址1的代码,发现原因在于这个后台线程是否为该类的成员函数。....
参考网址1:https://blog.csdn.net/xyisv/article/details/88292870
参考网址2:https://ask.csdn.net/questions/811874
1.问题及原因描述:
在使用pyqt5编写UI的时候,正如参考网址1所述,我们一般会将后台任务与界面区分,但我自己在实现的时候发现即使使用后台线程,但仍然会阻塞界面的操作,类似问题在参考网址2中也有提到。通过对比我自己的代码和参考网址1的代码,发现原因在于这个后台线程是否为该类的成员函数。
2.演示代码及描述:
以下是的在网址1的代码基础上进行修改后的示例演示。
from PyQt5 import QtWidgets, QtCore
import sys
from PyQt5.QtCore import *
import time
from PublicFunc import *
# 继承QThread
class Runthread(QtCore.QThread):
# 通过类成员对象定义信号对象
_signal = pyqtSignal(str)
def __init__(self):
super(Runthread, self).__init__()
def __del__(self):
self.wait()
def JudeIP(self, ipStr):
if ipStr == "0.0.0.0":
reIndex = 4
else:
ipTypeRe = isIpStr(ipStr)
if not ipTypeRe:
reIndex = 3
else:
# 检测IP能否ping通
pingIpRe = pingIp(ipStr)
if pingIpRe:
reIndex = 1
else:
reIndex = 2
return reIndex
def run(self):
for i in range(10):
reIndex = self.JudeIP("192.168.3.111")
print(str(i) + "--ping IP re:" + str(reIndex))
self._signal.emit(str((i+1)*10)) # 注意这里与_signal = pyqtSignal(str)中的类型相同
class Example(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.lineEid = QLineEdit()
# 进度条设置
self.pbar = QtWidgets.QProgressBar()
self.pbar.setGeometry(50, 50, 210, 25)
self.pbar.setValue(0)
# 按钮初始化
self.button1 = QtWidgets.QPushButton('开始(多线程为成员变量)')
self.button1.clicked.connect(self.start_login_m) # 绑定多线程(线程为成员变量)触发事件
self.button2 = QtWidgets.QPushButton('开始(多线程为局部变量)')
self.button2.clicked.connect(self.start_login) # 绑定多线程(线程为局部变量)触发事件
btnHBlayout = QHBoxLayout()
btnHBlayout.addWidget(self.button1)
btnHBlayout.addWidget(self.button2)
winVBlayout = QVBoxLayout()
winVBlayout.addWidget(self.lineEid)
winVBlayout.addWidget(self.pbar)
winVBlayout.addLayout(btnHBlayout)
self.setLayout(winVBlayout)
# 窗口初始化
self.setGeometry(300, 300, 300, 200)
self.setWindowTitle('耗时线程阻塞界面演示')
self.show()
self.thread = None # 初始化线程
def start_login(self):
self.pbar.setValue(0)
# 创建线程
thread = Runthread()
# 连接信号
thread._signal.connect(self.call_backlog) # 进程连接回传到GUI的事件
# 开始线程
thread.start()
def start_login_m(self):
self.pbar.setValue(0)
# 创建线程
self.thread = Runthread()
# 连接信号
self.thread._signal.connect(self.call_backlog) # 进程连接回传到GUI的事件
# 开始线程
self.thread.start()
def call_backlog(self, msg):
self.pbar.setValue(int(msg)) # 将线程的参数传入进度条
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
myshow = Example()
myshow.show()
sys.exit(app.exec_())
以下是该测试程序运行时的界面,当点击button1,即“开始(多线程为成员变量)”时,上方的lineEdit可以随意输入信息,同时进度条在以10%的速度刷新。但当点击button2,即“开始(多线程为局部变量)”时,点击lineEdit时界面阻塞,无法对界面进行操作,同时进度条也没有刷新,直到后台线程全部执行完毕,界面才能进行操作,lineEdit可以输入信息,进度条直接从0%变到100%。
3.原因分析:
以上两个按钮执行的函数,唯一的区别是阻塞按钮为局部变量,有可能是作用域不同造成的,这仅仅是我的猜测,若是有其他小伙伴知道原因,希望可以不吝赐教。
本文地址:https://blog.csdn.net/ali1174/article/details/109637838