Pyqt5:使用多线程QThread

 Pyqt5安装并配置到pycharm方法:完全弄懂如何用pycharm安装pyqt5及其相关配置

Pyqt5播放视频:Pyqt5:使用Qlabel标签进行视频播放

本内容是根据之前写的内容(Pyqt5播放视频)进行修改。

pyqt5处理多线程主要有三种方法:

  1. 使用计时器模块QTimer
  2. 使用多线程模块QThread
  3. 使用事件处理功能

QTimer相当于一个定时器,每当定时器时间溢出后,会执行相关的函数。这个时候程序会从主线程界面跳到QTimer函数中,如果QTimer函数中有延时或者处理时间较长,就会出现界面失去响应,造成界面卡顿的现象。

QThread等于新开一个线程专门处理耗时间的程序,UI主线程显示界面,当子线程处理好数据后通过自定义的信号与槽,将数据交给主线程刷新界面。由于UI主线程一直运行,子线程的延时,耗时程序与主线程无关,所以不会有卡顿的现象。

事件处理功能相当于在耗时的程序中,主动刷新界面,使人觉得流畅。

通过QThread实现多线程:

Qt有两种多线程的方法

第一种:是继承QThread的run函数

第二种:是把一个继承于QObject的类用moveToThread函数转移到一个Thread里。 

本例程中是使用第一种方法。

class VedioThread(QThread):
    sinout = pyqtSignal(str) # 自定义信号,执行run()函数时,从相关线程发射此信号

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

    def run(self):
        # 需要执行的内容
        xxxxx
        # 定义的槽函数,当xxxxx执行完成后就向UI界面(调用多线程的程序)发送一个指令,并让UI界面执行相应的内容。
        # str(1)-->发送的值,该值可以是xxxxx执行后返回的值,也可以是任意值(表示是否执行另一程序)
        self.sinout.emit(str(1))
        
        self.timeThread = VedioThread()  # 调用线程的程序
        self.timeThread.start()  # 开启线程
        self.timeThread.sinout.connect(self.xxxx)  # 接受到槽函数的值之后要执行的程序

 源码

  实例内容:UI播放视频,后台打印0-9,打印到9后,停止播放视频

from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
from PyQt5.uic import loadUiType
import cv2
import sys
import time

vedio_ui, _ = loadUiType('./UI/vedio.ui')


class VedioGui(QMainWindow, vedio_ui):
    # 定义构造方法
    def __init__(self):
        QMainWindow.__init__(self)
        self.setupUi(self)
        self.timer_camera = QTimer()
        self.handle_buttons()
        self.result_label.setText("按下start播放视频")
        self.open_vedio()
        self.timeThread = VedioThread()
        self.timeThread.sinout.connect(self.show_Stop)  # 将show_Stop与槽函数相连

    # 所有Button的消息与槽的通信
    def handle_buttons(self):
        self.btn_Start.clicked.connect(self.Btn_Start)
        self.btn_Stop.clicked.connect(self.Btn_Stop)

    def Btn_Start(self):
        self.timeThread.start()  # 开启线程
        # 定时器开启,每隔一段时间,读取一帧
        self.timer_camera.start(100)
        self.timer_camera.timeout.connect(self.OpenFrame)
        self.result_label.setText("正在播放")

    def Btn_Stop(self):
        # self.cap.release()
        self.timer_camera.stop()
        self.result_label.setText("停止播放,按下start再次播放")

    def open_vedio(self):
        """选取视频文件"""
        # 这里以mp4和avi视频播放为例
        openfile_name = QFileDialog.getOpenFileName(self, 'chose files', '', 'Image files(*.mp4 *.avi)')  # 打开文件选择框选择文件
        self.file_name = openfile_name[0]  # 获取图片名称

        # 得到文件后缀名  需要根据情况进行修改
        suffix = self.file_name.split("/")[-1][self.file_name.split("/")[-1].index(".") + 1:]
        # print(self.file_name, suffix)

        if self.file_name == '':
            pass
        elif suffix == "mp4" or suffix == "avi":
            self.cap = cv2.VideoCapture(self.file_name)

    def OpenFrame(self):
        ret, image = self.cap.read()
        if ret:
            if len(image.shape) == 3:
                image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)
            elif len(image.shape) == 1:
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_Indexed8)
            else:
                vedio_img = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)

            self.vedio_label.setPixmap(QPixmap(vedio_img))
            self.vedio_label.setScaledContents(True)  # 自适应窗口
        else:
            self.cap.release()
            self.timer_camera.stop()

    def show_Stop(self):
        self.Btn_Stop()

    # 界面关闭事件,询问用户是否关闭
    def closeEvent(self, event):
        reply = QMessageBox.question(self, '退出', "是否要退出该界面?",
                                     QMessageBox.Yes | QMessageBox.No, QMessageBox.No)
        if reply == QMessageBox.Yes:
            self.close()
            event.accept()
        else:
            event.ignore()


def show_print():
    for i in range(10):
        print(i)
        time.sleep(1)


class VedioThread(QThread):
    sinout = pyqtSignal(int)

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

    def run(self):
        # 需要执行的内容
        show_print()
        # 发出信号
        self.sinout.emit(1)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = VedioGui()
    window.show()
    sys.exit(app.exec_())

来源:牧子川

物联沃分享整理
物联沃-IOTWORD物联网 » Pyqt5:使用多线程QThread

发表评论