PyQt5自学记录(1) 您所在的位置:网站首页 pyqt5开启线程 PyQt5自学记录(1)

PyQt5自学记录(1)

2023-03-10 17:15| 来源: 网络整理| 查看: 265

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界面,实现逻辑界面和显示界面的分开,对新手来说无疑是一个福音。首先看一下整体的一个结构 卷积客户 therad.py是线程类文件,thread.ui是QtDesigner生成的UI文件,Thread_gui.py是由UI文件转换来的界面py文件,Thread_win.py是编写的逻辑文件。下面详细介绍多线程实现过程。 第一步:利用QtDesigner设计显示界面。并转换为py文件,也就是图中的thread.ui和Thread_gui.py文件。生成的Thread_gui.py不需要做任何更改,在逻辑文件中设置相关逻辑操作,Thread_gui.py代码如下

# -*- coding: utf-8 -*-# Form implementation generated from reading ui file 'untitled.ui' # # Created by: PyQt5 UI code generator 5.13.0 # # WARNING! All changes made in this file will be lost!from PyQt5 import QtCore, QtGui, QtWidgetsclass Ui_MainWindow(object):def setupUi(self, MainWindow):MainWindow.setObjectName("MainWindow")MainWindow.resize(436, 337)self.centralwidget = QtWidgets.QWidget(MainWindow)self.centralwidget.setObjectName("centralwidget")self.Button_Start = QtWidgets.QPushButton(self.centralwidget)self.Button_Start.setGeometry(QtCore.QRect(60, 200, 93, 28))self.Button_Start.setObjectName("pushButton")self.Button_Stop = QtWidgets.QPushButton(self.centralwidget)self.Button_Stop.setGeometry(QtCore.QRect(250, 200, 93, 28))self.Button_Stop.setObjectName("pushButton_2")self.label = QtWidgets.QLabel(self.centralwidget)self.label.setGeometry(QtCore.QRect(80, 90, 121, 41))self.label.setStyleSheet("background-color: rgb(85, 255, 255);")self.label.setText("")self.label.setObjectName("label")MainWindow.setCentralWidget(self.centralwidget)self.menubar = QtWidgets.QMenuBar(MainWindow)self.menubar.setGeometry(QtCore.QRect(0, 0, 436, 26))self.menubar.setObjectName("menubar")MainWindow.setMenuBar(self.menubar)self.statusbar = QtWidgets.QStatusBar(MainWindow)self.statusbar.setObjectName("statusbar")MainWindow.setStatusBar(self.statusbar)self.retranslateUi(MainWindow)QtCore.QMetaObject.connectSlotsByName(MainWindow)def retranslateUi(self, MainWindow):_translate = QtCore.QCoreApplication.translateMainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))self.Button_Start.setText(_translate("MainWindow", "Start"))self.Button_Stop.setText(_translate("MainWindow", "Stop"))

第二步:编写线程类文件,根据任务需求,在子线程中执行计时操作,并把事件返回到主线程中。定义一个线程类:首先要自定义信号,并把希望在线程中执行的操作写入类中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 实验室设备网 版权所有