在PyQt界面开发过程,有时候会遇到界面卡顿情况。经过多次试验,大部分原因是由于界面在进行数据查询过程耗时导致界面卡顿。解决方法建议采用多线程、多进程解决。
在界面更新函数加入time.sleep(2)即可阻断主界面执行完成,导致卡顿现象
def say(self,msg):
# 主界面更新如果耗时,那么主界面就会出现卡顿现象,下面这一行模拟主界面耗时,注释掉,主界面不会出现卡顿现象
time.sleep(3)
self.idx += 1
self.txtOutput.setText('%s[%d]' % (msg,self.idx)
代码名称:UiMain.py
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '.\UiMain.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again. Do not edit this file unless you know what you are doing.
from PyQt5 import QtCore, QtGui, QtWidgets
class Ui_Form(object):
def setupUi(self, Form):
Form.setObjectName("Form")
Form.resize(400, 300)
self.gridLayout = QtWidgets.QGridLayout(Form)
self.gridLayout.setObjectName("gridLayout")
self.label = QtWidgets.QLabel(Form)
self.label.setObjectName("label")
self.gridLayout.addWidget(self.label, 0, 0, 1, 1)
self.lnInput = QtWidgets.QLineEdit(Form)
self.lnInput.setObjectName("lnInput")
self.gridLayout.addWidget(self.lnInput, 0, 1, 1, 1)
self.bntBackupSelect = QtWidgets.QPushButton(Form)
self.bntBackupSelect.setObjectName("bntBackupSelect")
self.gridLayout.addWidget(self.bntBackupSelect, 0, 2, 1, 1)
self.txtOutput = QtWidgets.QTextBrowser(Form)
self.txtOutput.setObjectName("txtOutput")
self.gridLayout.addWidget(self.txtOutput, 1, 0, 1, 3)
self.retranslateUi(Form)
QtCore.QMetaObject.connectSlotsByName(Form)
def retranslateUi(self, Form):
_translate = QtCore.QCoreApplication.translate
Form.setWindowTitle(_translate("Form", "Form"))
self.label.setText(_translate("Form", "输入信息"))
self.bntBackupSelect.setText(_translate("Form", "后台查询"))
代码名称:testThread.py
# -*- coding: utf-8 -*-
import time
import pythoncom
import UiMain
from PyQt5 import QtCore
class ThreadCheckAnti(QtCore.QThread):
sinOut = QtCore.pyqtSignal(str) # 自定义信号,执行run()函数时,从相关线程发射此信号
def __init__(self,parent=None):
super(ThreadCheckAnti, self).__init__(parent)
def run(self):
pythoncom.CoInitialize()
while True:
time.sleep(1)
self.sinOut.emit('hi')
#释放资源
pythoncom.CoUninitialize()
from PyQt5.QtWidgets import QApplication , QWidget, QMessageBox
class WdtMain(QWidget,UiMain.Ui_Form):
def __init__(self, parent=None):
super(WdtMain, self).__init__(parent=parent)
self.setupUi(self)
self.initUI()
self.idx = 0
def __del__(self):
print(self.__class__,'del')
#self.thread.stop()
def initUI(self):
# 菜单模块
self.thread = ThreadCheckAnti()
self.thread.sinOut.connect(self.say)
self.thread.start()
#self.openBackRun()
def say(self,msg):
# 主界面更新如果耗时,那么主界面就会出现卡顿现象,下面这一行模拟主界面耗时,注释掉,主界面不会出现卡顿现象
time.sleep(3)
self.idx += 1
self.txtOutput.setText('%s[%d]' % (msg,self.idx))
if __name__=="__main__":
import sys
app = QApplication(sys.argv)
demo = WdtMain()
demo.show()
sys.exit(app.exec_())
以上案例虽然用到了线程,但是由于主界面的say函数由于比较耗时(2秒完成),而线程执行的速度又是1秒发送一次信号,导致主界面应接不暇。
解决思路:
say函数与线程互动,线程每次发送一次消息等待say返回信息再执行后续循环。
say与线程之间共用一个锁,每次线程执行之前加锁,发送完成之后,解锁;say函数修改界面之前加锁,修改完成之后解锁。
以上代码改动如下:
# -*- coding: utf-8 -*-
import time
import pythoncom
import UiMain
from PyQt5 import QtCore
from PyQt5.QtCore import QMutex
from multiprocessing import Queue
class ThreadCheckAnti(QtCore.QThread):
sinOut = QtCore.pyqtSignal(str) # 自定义信号,执行run()函数时,从相关线程发射此信号
def __init__(self,q_msg:Queue,q_lock:QMutex,parent=None):
super(ThreadCheckAnti, self).__init__(parent)
self.q_msg=q_msg
self.q_lock=q_lock
def run(self):
pythoncom.CoInitialize()
while True:
print('thread 准备 加锁...')
self.q_lock.lock()
print('thread 加锁 成功 ...')
time.sleep(1)
self.sinOut.emit('hi')
self.q_lock.unlock()
print('thread 释放锁 ...')
# 等待主界面消息
print('thread wait msg')
msg = self.q_msg.get()
print('say 反馈消息:', msg )
#释放资源
pythoncom.CoUninitialize()
from PyQt5.QtWidgets import QApplication , QWidget, QMessageBox
class WdtMain(QWidget,UiMain.Ui_Form):
def __init__(self, parent=None):
super(WdtMain, self).__init__(parent=parent)
self.setupUi(self)
self.initUI()
self.idx = 0
def __del__(self):
print(self.__class__,'del')
#self.thread.stop()
def initUI(self):
# 菜单模块
self.q_lock=QMutex()
self.q_msg =Queue()
self.thread = ThreadCheckAnti(q_lock=self.q_lock, q_msg=self.q_msg)
self.thread.sinOut.connect(self.say)
self.thread.start()
#self.openBackRun()
def say(self,msg):
self.q_lock.lock()
# 主界面更新如果耗时,那么主界面就会出现卡顿现象,下面这一行模拟主界面耗时,注释掉,主界面不会出现卡顿现象
time.sleep(3)
self.idx += 1
self.txtOutput.setText('%s[%d]' % (msg,self.idx))
self.q_lock.unlock()
self.q_msg.put('go')
if __name__=="__main__":
import sys
app = QApplication(sys.argv)
demo = WdtMain()
demo.show()
sys.exit(app.exec_())
解决效果:主界面在拖动过程不会出现“未响应”提示;由于say中sleep(3)在拖动过程还是会出现卡的感觉,这种是由于主界面是单进程缘故,所以在say执行耗时尽量减少到毫秒级别。