参考网址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%。

3.原因分析:

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

 

 

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