PyQt5自学记录(1) | 您所在的位置:网站首页 › pyqt5开启线程 › PyQt5自学记录(1) |
PyQt5自学记录(1)——PyQt5中多线程实现详解
最近想用PyQt5完成图像识别的一个GUI系统,在调用算法模型进行识别的时候,界面会卡住没有反应,所以想学习一下多线程解决这个问题。然后。。。发现没有基础学习来确实挺难,幸运地是最终实现了多线程,记录一下学习过程。如有错误,希望指正,一起进步。 进程和线程线程是一个轻负荷的子进程,是最小的处理单元。线程被包含在进程之中,是进程中的实际运作单位。一个进程可以并发多个线程,每条线程同时执行不同的任务,并且,线程是独立的,一个线程发生错误,不影响其他线程正常执行。 进程是指正在运行中的应用程序。每个进程都有自己独立的内存空间,当用户启动一个进程时,操作系统就会为该进程分配一个独立的内存空间,让应用程序在独立内存中运行 在实现多任务中,这篇博客中写到,要实现多任务,通常我们会设计Master-Worker模式,Master负责分配任务,Worker负责执行任务,因此,多任务环境下,通常是一个Master,多个Worker。如果用多进程实现Master-Worker,主进程就是Master,其他进程就是Worker。如果用多线程实现Master-Worker,主线程就是Master,其他线程就是Worker。在Windows系统下,多线程的效率要比多进程的效率要高。 PyQt5的多线程实现 PyQt5中自定义信号在介绍PyQt5的多线程实现之前,先介绍一下PyQt5中自定义信号的方法。 我们先来看一下PyQt5中自带的信号clicked的实现机制: self.Button_Start.clicked.connect(self.Start) A触发信号事件B 信号clickedC 接收信号做出相应操作通过鼠标点击(事件)触发信号,通过信号的传递控制相应的操作是否进行。自定义信号同样满足这种机制,自定义信号的机制与主要函数如下图: A触发信号事件emitB 声明信号 pyqtSignalC 接收信号做出相应操作connect首先要声明一个信号,通过信号名 = pyqtSignal(类型)实现 finishSignal = pyqtSignal(str) # 信号类型:str第二步要明确信号控制的操作,也就是槽函数。信号发出之后我们希望进行的操作,通过信号所在类实例.信号名.connect(槽函数)实现。 self.thread.finishSignal.connect(self.Change) # 信号挂接到槽:updatedef Change(self, msg):print(msg)self.label.setText(str(msg))最后一步,明确信号的触发机制,我们确定了信号以及信号控制的槽函数,那么什么时候发出这个消息呢,这就需要信号的触发机制,通过信号名.emit(信号内容)实现。 self.finishSignal.emit(str(i)) # 发射信号总结:emit(i)函数触发自定义信号将参数i发送给槽函数,槽函数接受信号,执行指定操作。 多线程实现理解了自定义信号PyQt5的多线程也就不难了,一个简单的例子看一下他的实现过程:主线程执行GUI界面,子线程用定时器读秒实时显示在主线程的GUI界面中。 通过QtDesigner设计GUI界面,实现逻辑界面和显示界面的分开,对新手来说无疑是一个福音。首先看一下整体的一个结构 第二步:编写线程类文件,根据任务需求,在子线程中执行计时操作,并把事件返回到主线程中。定义一个线程类:首先要自定义信号,并把希望在线程中执行的操作写入类中run( )函数中。线程类文件therad.py代码如下 # -*- coding: utf-8 -*- import time from PyQt5.QtCore import QThread, pyqtSignal#定义一个线程类 class New_Thread(QThread):#自定义信号声明# 使用自定义信号和UI主线程通讯,参数是发送信号时附带参数的数据类型,可以是str、int、list等finishSignal = pyqtSignal(str)# 带一个参数tdef __init__(self, t,parent=None):super(New_Thread, self).__init__(parent)self.t = t#run函数是子线程中的操作,线程启动后开始执行def run(self):for i in range(self.t):time.sleep(1)#发射自定义信号#通过emit函数将参数i传递给主线程,触发自定义信号self.finishSignal.emit(str(i)) # 注意这里与_signal = pyqtSignal(str)中的类型相同第三步:编写逻辑代码,首先要到导入前面两个文件,定义一个类包含相关逻辑操作。Thread_win.py代码如下 import sys from PyQt5.QtWidgets import QMainWindow, QApplication from Thread.Thread_gui import * from Thread.therad import New_Threadclass MainWindow(QMainWindow, Ui_MainWindow):def __init__(self, parent=None):super(MainWindow, self).__init__(parent)self.setupUi(self)# 绑定按钮点击事件self.Button_Start.clicked.connect(self.Start)self.Button_Stop.clicked.connect(self.Stop)def Stop(self):print('End')self.thread.terminate() # 终止线程def Start(self):print('Start clicked.')self.thread = New_Thread(t=100) #实例化一个线程,参数t设置为100# 将线程thread的信号finishSignal和UI主线程中的槽函数Change进行连接self.thread.finishSignal.connect(self.Change)# 启动线程,执行线程类中run函数self.thread.start()#接受通过emit传来的信息,执行相应操作def Change(self, msg):print(msg)self.label.setText(str(msg))if __name__ == '__main__':app = QApplication(sys.argv)main_window = MainWindow()main_window.show()sys.exit(app.exec_())通过以上三个文件就可以实现多线程操作了,运行Thread_win.py函数就可以实现。 (1)学习多线程首先要了解PyQt5中的自定义信号:包括三部分 声明信号 :信号名 = pyqtSignal(数据类型) 信号与槽函数连接:信号名.connect(槽函数) 自定义信号的触发:信号名.emit(参数) 注意:参数数据类型要和声明信号 的类型保持一致!!! (2)实现多线程时:首先要创建一个线程类,线程类中设置自定义信号,通过emit将信号发出(传递了参数),再由UI界面的槽函数接受,执行相关操作。 参考https://blog.csdn.net/foreveronly/article/details/82453697 https://blog.csdn.net/Mr_Zing/article/details/46945011 |
CopyRight 2018-2019 实验室设备网 版权所有 |