1、为什么使用线程

由于在PyQt5的GUI程序中只存在一个主线程,如果在主线程中进行非常耗时的操作,将会导致GUI界面卡死或者假死,这将十分影响程序的运行,因此在进行耗时的操作,比如有些地方需要使用while 语句,这将会十分耗时,因此使用线程。

2、开启线程的两种方式

(1)使用threading包,该方法简单,只需要两句就可以开启一个线程,进行多线程操作,但是该方法有一定的弊端,因为这是Python中的多线程方法,在QT中会被认为不是一个安全的线程,因此在该线程中不能更改主程序(进程)中任何控件的状态。例如设置lineEdit的text值,也是不可以的,当时可以获取主进程(程序)中控件的值,可以获取lineEdit的text值。通过自定义信号槽的机制应该也可以实现控件属性修改,参考另一篇博客  

from threading import Thread
class ServerMain(QMainWindow,Ui_Form):
    def __init__(self):
        super(ServerMain,self).__init__()
        self.setupUi(self)
        self.pushButton.clicked.connect(self.count_func)#调用函数
        
    def count_func(self):
        t = Thread(target=self.receive)#目标函数
        t.start()#启动线程

    def receive(self): #线程执行函数
        while True:
            print('-------')

(2)使用QThread类中的run方法,这个启动线程的方法中,可以更改主控件的值,使用的是迂回战术。通过自定义信号,信号发射和接收实现控件值得获取和更改。使用该方式需要重写QThread类中的run方法,因此需要多添加一个线程类

from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.QtGui import *

class ClientMain(QMainWindow,Ui_Form):

    def __init__(self):
        super(ClientMain,self).__init__()
        self.setupUi(self)
        #work = WorkThread(content)#类的实例化,也可以在此处实例化,但是如果在此处实例化,
        就不会获得控件的值,传递给线程中的run方法,因此在execute方法中实例化
        self.pushButton.clicked.connect(self.execute)#点击按钮,激活方法

    def execute(self):        
        content = self.textEdit.toPlainText()#获取textEdit中的内容
        work = WorkThread(content)#类的实例化
        work.start()#开启线程
        work.signals.connect(self.settexts)#信号连接槽函数

    def settexts(self,texts):#带有一个str参数,用来接收自定义信号传递的值
        print(texts+'已经改变')#接收到自定义信号的值
        self.textEdit_2.setText(texts)#设置主控件中textEdit的值

# 继承QThread,重写run方法
class WorkThread(QtCore.QThread):    
    signals = pyqtSignal(str)# 定义信号对象,传递值为str类型,使用int,可以为int类型
    
    def __init__(self,content):#向线程中传递参数,以便在run方法中使用
        super(WorkThread, self).__init__()       
        self.content = content
        
    def __del__(self):
        self.wait()
        
    def run(self):#重写run方法
        while True:
            print(self.content)
            self.signals.emit('接收到服务器数据')#发射信号,str类型数据,内容为需要传递的数据