PyQt开发中,往往遇到UI事件处理时间过长,导致界面出现无响应,用户体验很差。
解决的办法很简单,UI与逻辑处理线程分离即可,UI线程只负责更新UI,逻辑代码新开线程进行处理即可,这样子,界面就不会出现卡死无响应状态。
以一个简单的例子讲解。
开发工具:Eric 6, PyQt 4.8, Python 3.4.3
1:用Eric设计好一个窗口,添加一个按钮,通过Eric自动生成代码;
2:自动生成代码,代码如下:
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
"""
from PyQt4.QtCore import pyqtSlot
from PyQt4.QtGui import QMainWindow
from PyQt4 import QtCore, QtGui
import time
from Ui_main import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
@param parent reference to the parent widget
@type QWidget
"""
super(MainWindow, self).__init__(parent)
self.setupUi(self)
@pyqtSlot()
def on_pushButton_login_clicked(self):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
pass
@pyqtSlot(list)
def LoginEnd(self, words):
for i in words:
print(i)
self.pushButton_login.setDisabled(False)
pass
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
3:处理登陆按钮点击事件,我们在UI线程里直接写:
@pyqtSlot()
def on_pushButton_login_clicked(self):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
self.pushButton_login.setDisabled(True)
#采用单线程操作
time.sleep(6)
print("hello, world")
self.pushButton_login.setDisabled(False)
这样子,运行起来后,用户体验比较差,因为同在一个线程里,当sleep的时候,UI线程也无法操作,故出现无响应状态。如下状态:
这种体验非常糟糕,而且很容易由于用户多次点击程序挂掉。下面提供解决办法:
1:将点击登录按钮之后的操作,我们通过线程进行操作即可,声明一个线程操作类如下:
#coding='utf-8'
from PyQt4 import QtCore, QtGui
import time
class LoginHandler(QtCore.QThread):
finishSignal = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(LoginHandler, self).__init__(parent)
pass
def run(self):
time.sleep(6)
self.finishSignal.emit(['hello,','world','!'])
2:点击按钮时调用该线程类:
@pyqtSlot()
def on_pushButton_login_clicked(self):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
self.pushButton_login.setDisabled(True)
#采用单线程操作
#time.sleep(6)
#print("hello, world")
#self.pushButton_login.setDisabled(False)
#采用多线程操作
from LoginHandler import LoginHandler
self.login_process = LoginHandler()
#登陆完成的信号绑定到登陆结束的槽函数
self.login_process.finishSignal.connect(self.LoginEnd)
#启动线程
self.login_process.start()
pass
通过这种方式处理后,界面就不会出现无响应的状态。
附所有代码:
Ui_main.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file 'E:\demo_project\pyqt_demo\main.ui'
#
# Created by: PyQt4 UI code generator 4.11.4
#
# WARNING! All changes made in this file will be lost!
from PyQt4 import QtCore, QtGui
try:
_fromUtf8 = QtCore.QString.fromUtf8
except AttributeError:
def _fromUtf8(s):
return s
try:
_encoding = QtGui.QApplication.UnicodeUTF8
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig, _encoding)
except AttributeError:
def _translate(context, text, disambig):
return QtGui.QApplication.translate(context, text, disambig)
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName(_fromUtf8("MainWindow"))
MainWindow.resize(475, 264)
self.centralWidget = QtGui.QWidget(MainWindow)
self.centralWidget.setObjectName(_fromUtf8("centralWidget"))
self.pushButton_login = QtGui.QPushButton(self.centralWidget)
self.pushButton_login.setGeometry(QtCore.QRect(102, 66, 257, 95))
self.pushButton_login.setStyleSheet(_fromUtf8("font: 18pt \"Adobe Devanagari\";"))
self.pushButton_login.setObjectName(_fromUtf8("pushButton_login"))
MainWindow.setCentralWidget(self.centralWidget)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow", None))
self.pushButton_login.setText(_translate("MainWindow", "点击我登陆", None))
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
MainWindow = QtGui.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
main.py:
# -*- coding: utf-8 -*-
"""
Module implementing MainWindow.
"""
from PyQt4.QtCore import pyqtSlot
from PyQt4.QtGui import QMainWindow
from PyQt4 import QtCore, QtGui
import time
from Ui_main import Ui_MainWindow
class MainWindow(QMainWindow, Ui_MainWindow):
"""
Class documentation goes here.
"""
def __init__(self, parent=None):
"""
Constructor
@param parent reference to the parent widget
@type QWidget
"""
super(MainWindow, self).__init__(parent)
self.setupUi(self)
@pyqtSlot()
def on_pushButton_login_clicked(self):
"""
Slot documentation goes here.
"""
# TODO: not implemented yet
self.pushButton_login.setDisabled(True)
#采用单线程操作
#time.sleep(6)
#print("hello, world")
#self.pushButton_login.setDisabled(False)
#采用多线程操作
from LoginHandler import LoginHandler
self.login_process = LoginHandler()
#登陆完成的信号绑定到登陆结束的槽函数
self.login_process.finishSignal.connect(self.LoginEnd)
#启动线程
self.login_process.start()
pass
@pyqtSlot(list)
def LoginEnd(self, words):
for i in words:
print(i)
self.pushButton_login.setDisabled(False)
pass
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
win = MainWindow()
win.show()
sys.exit(app.exec_())
LoginHandler.py:
#coding='utf-8'
from PyQt4 import QtCore, QtGui
import time
class LoginHandler(QtCore.QThread):
finishSignal = QtCore.pyqtSignal(list)
def __init__(self, parent=None):
super(LoginHandler, self).__init__(parent)
pass
def run(self):
time.sleep(6)
self.finishSignal.emit(['hello,','world','!'])
文章的脚注信息由WordPress的wp-posturl插件自动生成


微信扫一扫,打赏作者吧~![[整理]how to run flask with pyqt5](http://www.jyguagua.com/wp-content/themes/begin/timthumb.php?src=http://www.jyguagua.com/wp-content/uploads/2021/03/pyqt_flask.png&w=280&h=210&zc=1)
![[已解决]LINK : fatal error LNK1158: cannot run 'rc.exe' 错误的解决办法](http://www.jyguagua.com/wp-content/themes/begin/timthumb.php?src=http://www.jyguagua.com/wp-content/uploads/2021/02/Snipaste_2021-02-17_15-18-26-1024x505.png&w=280&h=210&zc=1)
![[已解决]Python扩展模块 error: Unable to find vcvarsall.bat](http://www.jyguagua.com/wp-content/themes/begin/timthumb.php?src=http://www.jyguagua.com/wp-content/uploads/2020/11/Snipaste_2020-11-19_10-01-38.png&w=280&h=210&zc=1)
![[整理]PyQt画圆,动态变色](http://www.jyguagua.com/wp-content/themes/begin/timthumb.php?src=http://www.jyguagua.com/wp-content/uploads/2020/08/drawCircle.gif&w=280&h=210&zc=1)