欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

pyqt5耗时线程阻塞界面

程序员文章站 2022-03-28 16:05:50
参考网址1:https://blog.csdn.net/xyisv/article/details/88292870参考网址2:https://ask.csdn.net/questions/8118741.问题及原因描述:在使用pyqt5编写UI的时候,正如参考网址1所述,我们一般会将后台任务与界面区分,但我自己在实现的时候发现即使使用后台线程,但仍然会阻塞界面的操作,类似问题在参考网址2中也有提到。通过对比我自己的代码和参考网址1的代码,发现原因在于这个后台线程是否为该类的成员函数。....

参考网址1:https://blog.csdn.net/xyisv/article/details/88292870

参考网址2:https://ask.csdn.net/questions/811874

 

1.问题及原因描述:

在使用pyqt5编写UI的时候,正如参考网址1所述,我们一般会将后台任务与界面区分,但我自己在实现的时候发现即使使用后台线程,但仍然会阻塞界面的操作,类似问题在参考网址2中也有提到。通过对比我自己的代码和参考网址1的代码,发现原因在于这个后台线程是否为该类的成员函数。

 

2.演示代码及描述:

以下是的在网址1的代码基础上进行修改后的示例演示。

from PyQt5 import QtWidgets, QtCore
import sys
from PyQt5.QtCore import *
import time
from PublicFunc import *

# 继承QThread
class Runthread(QtCore.QThread):
    #  通过类成员对象定义信号对象
    _signal = pyqtSignal(str)

    def __init__(self):
        super(Runthread, self).__init__()

    def __del__(self):
        self.wait()

    def JudeIP(self, ipStr):
        if ipStr == "0.0.0.0":
            reIndex = 4
        else:
            ipTypeRe = isIpStr(ipStr)
            if not ipTypeRe:
                reIndex = 3
            else:
                # 检测IP能否ping通
                pingIpRe = pingIp(ipStr)
                if pingIpRe:
                    reIndex = 1
                else:
                    reIndex = 2
        return reIndex

    def run(self):
        for i in range(10):
            reIndex = self.JudeIP("192.168.3.111")
            print(str(i) + "--ping IP re:" + str(reIndex))
            self._signal.emit(str((i+1)*10))  # 注意这里与_signal = pyqtSignal(str)中的类型相同


class Example(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()
        self.lineEid = QLineEdit()

        # 进度条设置
        self.pbar = QtWidgets.QProgressBar()
        self.pbar.setGeometry(50, 50, 210, 25)
        self.pbar.setValue(0)

        # 按钮初始化
        self.button1 = QtWidgets.QPushButton('开始(多线程为成员变量)')
        self.button1.clicked.connect(self.start_login_m)  # 绑定多线程(线程为成员变量)触发事件
        self.button2 = QtWidgets.QPushButton('开始(多线程为局部变量)')
        self.button2.clicked.connect(self.start_login)  # 绑定多线程(线程为局部变量)触发事件

        btnHBlayout = QHBoxLayout()
        btnHBlayout.addWidget(self.button1)
        btnHBlayout.addWidget(self.button2)

        winVBlayout = QVBoxLayout()
        winVBlayout.addWidget(self.lineEid)
        winVBlayout.addWidget(self.pbar)
        winVBlayout.addLayout(btnHBlayout)
        self.setLayout(winVBlayout)

        # 窗口初始化
        self.setGeometry(300, 300, 300, 200)
        self.setWindowTitle('耗时线程阻塞界面演示')
        self.show()

        self.thread = None  # 初始化线程

    def start_login(self):
        self.pbar.setValue(0)
        # 创建线程
        thread = Runthread()
        # 连接信号
        thread._signal.connect(self.call_backlog)  # 进程连接回传到GUI的事件
        # 开始线程
        thread.start()

    def start_login_m(self):
        self.pbar.setValue(0)
        # 创建线程
        self.thread = Runthread()
        # 连接信号
        self.thread._signal.connect(self.call_backlog)  # 进程连接回传到GUI的事件
        # 开始线程
        self.thread.start()

    def call_backlog(self, msg):
        self.pbar.setValue(int(msg))  # 将线程的参数传入进度条


if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    myshow = Example()
    myshow.show()
    sys.exit(app.exec_())

以下是该测试程序运行时的界面,当点击button1,即“开始(多线程为成员变量)”时,上方的lineEdit可以随意输入信息,同时进度条在以10%的速度刷新。但当点击button2,即“开始(多线程为局部变量)”时,点击lineEdit时界面阻塞,无法对界面进行操作,同时进度条也没有刷新,直到后台线程全部执行完毕,界面才能进行操作,lineEdit可以输入信息,进度条直接从0%变到100%。

pyqt5耗时线程阻塞界面

3.原因分析:

以上两个按钮执行的函数,唯一的区别是阻塞按钮为局部变量,有可能是作用域不同造成的,这仅仅是我的猜测,若是有其他小伙伴知道原因,希望可以不吝赐教。

 

 

本文地址:https://blog.csdn.net/ali1174/article/details/109637838