在Pyqt5程序中经常出现耗时的操作,这个时候一般使用Qthread或者Qtimer将耗时操作交给新的线程。
今天发现了一个导致UI卡顿的情形,代码如下:
from PyQt5 import QtWidgets
import sys
from PyQt5.QtCore import *
import time
class UI_(object):
def __init__(self, parent=None):
self.textEdit = QtWidgets.QListWidget(parent=parent)
self.textEdit.setGeometry(QRect(0, 0, 100, 100))
self.bn = QtWidgets.QPushButton(text='点击', parent=parent)
self.bn.setGeometry(QRect(100, 250, 40, 20))
self.tex = QtWidgets.QPlainTextEdit(parent=parent)
self.tex.setGeometry(QRect(300, 300, 100, 100))
self.bn.clicked.connect(self.act)
def act(self):
self.timer = QTimer()
self.timer.timeout.connect(self.pp)
self.timer.start(1000)
def pp(self):
# 发送报文
time.sleep(0.4)
# 接收报文
print(str(1))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
window.setGeometry(QRect(500, 500, 400, 400))
ui = UI_(window)
window.show()
app.exec_()
这段代码模拟端口每隔1秒向服务器发送报文,在发送报文0.4秒后读取服务器返回内容。这个时候会出现UI界面卡顿的情况。这是因为time库是由python写的,Qt是由cpp写的,在sleep等待时,Qt程序被迫阻塞。
解决方法:将timer.sleep()放在QThread中。
from PyQt5 import QtWidgets
import sys
from PyQt5.QtCore import *
import time
class UI_(object):
def __init__(self, parent=None):
self.textEdit = QtWidgets.QListWidget(parent=parent)
self.textEdit.setGeometry(QRect(0, 0, 100, 100))
self.bn = QtWidgets.QPushButton(parent=parent)
self.bn.setGeometry(QRect(100, 250, 20, 20))
self.tex = QtWidgets.QPlainTextEdit(parent=parent)
self.tex.setGeometry(QRect(300, 300, 100, 100))
self.work = WorkThread()
self.bn.clicked.connect(self.act)
def act(self):
self.work.start()
self.work.sig.connect(self.display)
def display(self, str):
self.textEdit.addItem(str)
class WorkThread(QThread):
# 自定义信号对象,参数str表示这个信号可以传递一个字符串
sig = pyqtSignal(str)
def __init__(self):
super().__init__()
# 重写线程执行的run函数触发自定义信号
def run(self):
while True:
time.sleep(1)
# 通过自定义信号把待显示的字符串传递给槽函数
self.sig.emit(str(1))
if __name__ == '__main__':
app = QtWidgets.QApplication(sys.argv)
window = QtWidgets.QMainWindow()
window.setGeometry(QRect(500, 500, 400, 400))
ui = UI_(window)
window.show()
app.exec_()