Pyqt5:使用多线程QThread
Pyqt5安装并配置到pycharm方法:完全弄懂如何用pycharm安装pyqt5及其相关配置
Pyqt5播放视频:Pyqt5:使用Qlabel标签进行视频播放
本内容是根据之前写的内容(Pyqt5播放视频)进行修改。
pyqt5处理多线程主要有三种方法:
- 使用计时器模块QTimer
- 使用多线程模块QThread
- 使用事件处理功能
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_())
来源:牧子川