[分享]PyQt UI与后台逻辑操作线程分离(PyQt登陆窗口设计为例讲解)

PyQt开发中,往往遇到UI事件处理时间过长,导致界面出现无响应,用户体验很差。

解决的办法很简单,UI与逻辑处理线程分离即可,UI线程只负责更新UI,逻辑代码新开线程进行处理即可,这样子,界面就不会出现卡死无响应状态。

以一个简单的例子讲解。

开发工具:Eric 6, PyQt 4.8, Python 3.4.3

1:用Eric设计好一个窗口,添加一个按钮,通过Eric自动生成代码;

login1

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线程也无法操作,故出现无响应状态。如下状态:

login2

 

这种体验非常糟糕,而且很容易由于用户多次点击程序挂掉。下面提供解决办法:

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插件自动生成



|2|left
打赏

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: