@ pyqt5多线程
pyqt5运行程序时,如果程序消耗时间过久,就会出现界面假死的情况,解决方法可以将耗时过久的程序放到线程中。
一,重写QThread类
#需要加载模块中的QThread和pyqtSignal
from PyQt5.QtCore import QThread,pyqtSignal
class MyThread(QThread):
Signal1 = pyqtSignal(str) #自定义触发信号
def __init__(self, count):
super().__init__()
self.count = count
def run(self): #run方法重写
for i in range(self.count):
self.Signal1.emit(str(i)) #发送信号,触发槽函数
time.sleep(1) #添加时延
1,自定义触发信号
pyqtSignal()自定义触发信号,为类变量 ,参数类型可以是str,int,None,list等多种形式,表示触发的信号类型。
2,run()
在自定义的线程类中重写run()方法。run()方法中写线程功能,一般是耗时较久或者重复执行的功能。
3,emit()
emit()用于触发槽函数,参数类型与pyqtSignal()的参数类型一样,表示触发信号的类型。emit()的参数会传给此信号连接的槽函数。
4,论时延的重要性
初看别人的介绍时,一直不理解为什么都要在最后添加时延,直到自己的程序执行时,添加多线程后仍然出现界面假死才明白时延的重要性。
如果线程函数触发槽函数为循环触发,且每次循环中运行时间过短的话,线程频繁触发槽函数,访问主界面的间隔过短,会表现为主界面一直运行,界面卡顿。
二,线程执行
self.Thread1 = MyThread(10) #创建线程实例
self.Thread1.Signal1.connect(self.threadFunc) #自定义的信号连接到槽函数
self.Thread1.start() #开始执行
1,首先进行实例化,创建一个线程实例,并对其进行初始化。
2,线程执行时依然遵循qt的信号与槽函数机制,通过重写Qthread类中自定义的触发信号,线程触发Signal1信号,连接到槽函数threadFunc,槽函数与界面进行交互,即将功能与UI分开,run()函数中执行功能部分,槽函数中执行界面交互。线程与槽函数传递参数是通过emit()触发函数传递的。
3,执行start()时,线程开始执行,将自动执行线程类中的run()函数。
三,时序
主线程执行,执行到子线程的start(),主线程继续执行,子线程自动跳到run()函数,执行子线程功能。直到emit()触发信号到threadFun槽函数,与UI交互,返回到主线程。此时,若主线程代码段执行完毕,则执行槽函数,主线程代码段未执行完,等到主线代码段程执行完,再执行槽函数。
四,代码示例
贴一段自己随便写的代码记录
import time
import sys
from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import QThread,pyqtSignal
from PyQt5.QtSerialPort import QSerialPortInfo
from TestUI import Ui_Form #UI
#自定义线程类省略
#界面交互
class QmyMainWindow(QWidget):
def __init__(self):
QWidget.__init__(self)
# self.setupUi()
self.Ui_Form = Ui_Form()
self.Ui_Form.setupUi(self)
# 禁用最大化和窗口拉伸
self.setFixedSize(self.width(),self.height())
def closeEvent(self, event):
reply = QMessageBox.question(self, 'Information',"Are you sure to quit?", QMessageBox.Yes|QMessageBox.No, QMessageBox.Yes)
if reply == QMessageBox.Yes:
event.accept()
else:
event.ignore()
def threadFunc(self,content):#线程槽函数
self.Ui_Form.lineEdit.setText(content)
return
def thread1(self):#UI按键槽函数
self.Thread1 = MyThread(10)
self.Thread1.Signal1.connect(self.threadFunc)
self.Thread1.start()
def thread2(self):#UI按键槽函数
self.Thread2 = MyThread(20)
self.Thread2.Signal1.connect(self.threadFunc)
self.Thread2.start()
if __name__=="__main__":
app = QApplication(sys.argv)
MainWin = QmyMainWindow()
MainWin.show()
sys.exit(app.exec_())
#Qt designer生成的UI TestUI.py
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(530, 471)
self.lineEdit = QtWidgets.QLineEdit(Form)
self.lineEdit.setGeometry(QtCore.QRect(100, 180, 331, 21))
self.lineEdit.setObjectName("lineEdit")
self.Run = QtWidgets.QPushButton(Form)
self.Run.setGeometry(QtCore.QRect(120, 260, 93, 28))
self.Run.setObjectName("Run")
self.Stop = QtWidgets.QPushButton(Form)
self.Stop.setGeometry(QtCore.QRect(310, 260, 93, 28))
self.Stop.setObjectName("Stop")
self.retranslateUi(Form)
self.Run.clicked.connect(Form.thread1)
self.Stop.clicked.connect(Form.thread2)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.Run.setText(_translate("Form", "Thread1"))
self.Stop.setText(_translate("Form", "Thread2"))
效果图