两种不同功能的 QTreading 实现 - PyQT5
QTreading implementation for two different functions - PyQT5
我一直在尝试使用 QThreads 在 PyQT5 上实现多线程。我想同时显示视频和更新一组标签(我以计数器为例)。根据我的研究,我发现了实现 QThreads 的不同方法,recommended 使用以下方法而不是实例化 QTread 和修改 运行 方法,所以我听从了那个建议。这是我的简化代码:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import os
import cv2
import numpy as np
import time
############################# Telemtry widgets update ##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr >50):
cntr = 0
self.finished.emit()
######################################################################################
class VideoThread(QObject):
ImageUpdate = pyqtSignal(QImage)
frame_cv = pyqtSignal(np.ndarray)
started = pyqtSignal()
finished = pyqtSignal()
frame=[]
def run(self):
self.display_width= 1280
self.display_height = 720
self.ThreadActive = True
Capture = cv2.VideoCapture('sample.mp4')
while Capture.isOpened():
ret, self.frame = Capture.read()
if ret:
Image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
ConvertToQtFormat = QImage(Image.data, Image.shape[1], Image.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(self.display_width, self.display_height, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
time.sleep(30/1000) #use it just when playing from a file to memic FPS delay
Capture.release()
self.finished.emit()
def sel(self):
self.frame_cv.emit(self.frame)
############################ GUI #######################################
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1920, 1080)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.vid = QtWidgets.QLabel(self.centralwidget)
self.vid.setGeometry(QtCore.QRect(550, 70, 1280, 720))
self.vid.setFrameShape(QtWidgets.QFrame.Box)
self.vid.setText("")
self.vid.setObjectName("vid")
self.vid.setFocusPolicy(Qt.StrongFocus) #important to be able to listen to a keypress
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(220, 420, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
self.worker1.finished.connect(self.thread1.quit)
self.worker1.finished.connect(self.worker1.deleteLater)
self.thread1.finished.connect(self.thread1.deleteLater)
self.thread1.start()
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
print(str(acc_val))
############### video thread ############################3
self.thread2 = QThread()
self.worker2 = VideoThread()
self.worker2.moveToThread(self.thread2)
self.thread2.started.connect(self.worker2.run)
self.worker2.finished.connect(self.thread2.quit)
self.worker2.finished.connect(self.worker2.deleteLater)
self.thread2.finished.connect(self.thread2.deleteLater)
# connect its signal to the update_image slot
self.worker2.ImageUpdate.connect(self.ImageUpdateSlot)
# start the thread
self.thread2.start()
def ImageUpdateSlot(self, Image):
self.vid.setPixmap(QPixmap.fromImage(Image))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Title.setText(_translate("MainWindow", "TEST"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
当我 运行 它时,我收到以下错误:
1
2
QThread: Destroyed while thread is still running
Aborted (core dumped)
什么是最好的实现方式,在这种情况下可以使用普通线程代替 QThreads 吗?
谢谢
我想通了,出于某种原因我错误地在 Label_update 中定义了 worker2,我只是将 Label_update 方法向下移动并按照 musicanante 的评论进行操作,现在它开始工作了。如果有人感兴趣,这里是完整的工作代码。
############################# Telemtry 小部件更新
##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr >50):
cntr = 0
self.finished.emit()
######################################################################################
class VideoThread(QObject):
ImageUpdate = pyqtSignal(QImage)
frame_cv = pyqtSignal(np.ndarray)
started = pyqtSignal()
finished = pyqtSignal()
frame=[]
def run(self):
self.display_width= 1280
self.display_height = 720
self.ThreadActive = True
Capture = cv2.VideoCapture('sample.mp4')
while Capture.isOpened():
ret, self.frame = Capture.read()
if ret:
Image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
ConvertToQtFormat = QImage(Image.data, Image.shape[1], Image.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(self.display_width, self.display_height, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
time.sleep(30/1000) #use it just when playing from a file to memic FPS delay
Capture.release()
self.finished.emit()
def sel(self):
self.frame_cv.emit(self.frame)
############################ GUI #######################################
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1920, 1080)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.vid = QtWidgets.QLabel(self.centralwidget)
self.vid.setGeometry(QtCore.QRect(550, 70, 1280, 720))
self.vid.setFrameShape(QtWidgets.QFrame.Box)
self.vid.setText("")
self.vid.setObjectName("vid")
self.vid.setFocusPolicy(Qt.StrongFocus) #important to be able to listen to a keypress
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(220, 420, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
#self.worker1.finished.connect(self.thread1.quit)
#self.worker1.finished.connect(self.worker1.deleteLater)
self.thread1.finished.connect(self.worker1.deleteLater)
self.thread1.start()
############### video thread ############################3
self.thread2 = QThread()
self.worker2 = VideoThread()
self.worker2.moveToThread(self.thread2)
self.thread2.started.connect(self.worker2.run)
#self.worker2.finished.connect(self.thread2.quit)
#self.worker2.finished.connect(self.worker2.deleteLater)
self.thread2.finished.connect(self.worker2.deleteLater)
# connect its signal to the update_image slot
self.worker2.ImageUpdate.connect(self.ImageUpdateSlot)
# start the thread
self.thread2.start()
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
print(str(acc_val))
def ImageUpdateSlot(self, Image):
self.vid.setPixmap(QPixmap.fromImage(Image))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Title.setText(_translate("MainWindow", "TEST"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
我一直在尝试使用 QThreads 在 PyQT5 上实现多线程。我想同时显示视频和更新一组标签(我以计数器为例)。根据我的研究,我发现了实现 QThreads 的不同方法,recommended 使用以下方法而不是实例化 QTread 和修改 运行 方法,所以我听从了那个建议。这是我的简化代码:
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import QPoint, QRect, QSize, Qt
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from PyQt5.QtCore import *
import sys
import os
import cv2
import numpy as np
import time
############################# Telemtry widgets update ##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr >50):
cntr = 0
self.finished.emit()
######################################################################################
class VideoThread(QObject):
ImageUpdate = pyqtSignal(QImage)
frame_cv = pyqtSignal(np.ndarray)
started = pyqtSignal()
finished = pyqtSignal()
frame=[]
def run(self):
self.display_width= 1280
self.display_height = 720
self.ThreadActive = True
Capture = cv2.VideoCapture('sample.mp4')
while Capture.isOpened():
ret, self.frame = Capture.read()
if ret:
Image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
ConvertToQtFormat = QImage(Image.data, Image.shape[1], Image.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(self.display_width, self.display_height, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
time.sleep(30/1000) #use it just when playing from a file to memic FPS delay
Capture.release()
self.finished.emit()
def sel(self):
self.frame_cv.emit(self.frame)
############################ GUI #######################################
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1920, 1080)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.vid = QtWidgets.QLabel(self.centralwidget)
self.vid.setGeometry(QtCore.QRect(550, 70, 1280, 720))
self.vid.setFrameShape(QtWidgets.QFrame.Box)
self.vid.setText("")
self.vid.setObjectName("vid")
self.vid.setFocusPolicy(Qt.StrongFocus) #important to be able to listen to a keypress
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(220, 420, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
self.worker1.finished.connect(self.thread1.quit)
self.worker1.finished.connect(self.worker1.deleteLater)
self.thread1.finished.connect(self.thread1.deleteLater)
self.thread1.start()
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
print(str(acc_val))
############### video thread ############################3
self.thread2 = QThread()
self.worker2 = VideoThread()
self.worker2.moveToThread(self.thread2)
self.thread2.started.connect(self.worker2.run)
self.worker2.finished.connect(self.thread2.quit)
self.worker2.finished.connect(self.worker2.deleteLater)
self.thread2.finished.connect(self.thread2.deleteLater)
# connect its signal to the update_image slot
self.worker2.ImageUpdate.connect(self.ImageUpdateSlot)
# start the thread
self.thread2.start()
def ImageUpdateSlot(self, Image):
self.vid.setPixmap(QPixmap.fromImage(Image))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Title.setText(_translate("MainWindow", "TEST"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())
当我 运行 它时,我收到以下错误:
1
2
QThread: Destroyed while thread is still running
Aborted (core dumped)
什么是最好的实现方式,在这种情况下可以使用普通线程代替 QThreads 吗?
谢谢
我想通了,出于某种原因我错误地在 Label_update 中定义了 worker2,我只是将 Label_update 方法向下移动并按照 musicanante 的评论进行操作,现在它开始工作了。如果有人感兴趣,这里是完整的工作代码。
############################# Telemtry 小部件更新
##########################
class DISPLAY(QObject):
acc1_val = pyqtSignal(int)
finished = pyqtSignal()
def run(self):
global cntr
cntr = 0
while 1:
cntr = cntr +1
time.sleep(1)
self.acc1_val.emit(cntr)
if(cntr >50):
cntr = 0
self.finished.emit()
######################################################################################
class VideoThread(QObject):
ImageUpdate = pyqtSignal(QImage)
frame_cv = pyqtSignal(np.ndarray)
started = pyqtSignal()
finished = pyqtSignal()
frame=[]
def run(self):
self.display_width= 1280
self.display_height = 720
self.ThreadActive = True
Capture = cv2.VideoCapture('sample.mp4')
while Capture.isOpened():
ret, self.frame = Capture.read()
if ret:
Image = cv2.cvtColor(self.frame, cv2.COLOR_BGR2RGB)
ConvertToQtFormat = QImage(Image.data, Image.shape[1], Image.shape[0], QImage.Format_RGB888)
Pic = ConvertToQtFormat.scaled(self.display_width, self.display_height, Qt.KeepAspectRatio)
self.ImageUpdate.emit(Pic)
time.sleep(30/1000) #use it just when playing from a file to memic FPS delay
Capture.release()
self.finished.emit()
def sel(self):
self.frame_cv.emit(self.frame)
############################ GUI #######################################
class Ui_MainWindow(object):
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(1920, 1080)
MainWindow.setFocusPolicy(QtCore.Qt.NoFocus)
self.centralwidget = QtWidgets.QWidget(MainWindow)
self.centralwidget.setObjectName("centralwidget")
self.vid = QtWidgets.QLabel(self.centralwidget)
self.vid.setGeometry(QtCore.QRect(550, 70, 1280, 720))
self.vid.setFrameShape(QtWidgets.QFrame.Box)
self.vid.setText("")
self.vid.setObjectName("vid")
self.vid.setFocusPolicy(Qt.StrongFocus) #important to be able to listen to a keypress
self.Title = QtWidgets.QLabel(self.centralwidget)
self.Title.setGeometry(QtCore.QRect(30, 10, 421, 71))
font = QtGui.QFont()
font.setPointSize(24)
font.setBold(True)
font.setWeight(75)
self.Title.setFont(font)
self.Title.setObjectName("Title")
self.ACC1_X = QtWidgets.QLineEdit(self.centralwidget)
self.ACC1_X.setGeometry(QtCore.QRect(220, 420, 41, 31))
self.ACC1_X.setObjectName("ACC1_X")
MainWindow.setCentralWidget(self.centralwidget)
self.menubar = QtWidgets.QMenuBar(MainWindow)
self.menubar.setGeometry(QtCore.QRect(0, 0, 1920, 22))
self.menubar.setObjectName("menubar")
MainWindow.setMenuBar(self.menubar)
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
###################### Display thread ######################
self.thread1 = QThread()
self.worker1 = DISPLAY()
self.worker1.moveToThread(self.thread1)
self.thread1.started.connect(self.worker1.run)
self.worker1.acc1_val.connect(self.Label_update)
#self.worker1.finished.connect(self.thread1.quit)
#self.worker1.finished.connect(self.worker1.deleteLater)
self.thread1.finished.connect(self.worker1.deleteLater)
self.thread1.start()
############### video thread ############################3
self.thread2 = QThread()
self.worker2 = VideoThread()
self.worker2.moveToThread(self.thread2)
self.thread2.started.connect(self.worker2.run)
#self.worker2.finished.connect(self.thread2.quit)
#self.worker2.finished.connect(self.worker2.deleteLater)
self.thread2.finished.connect(self.worker2.deleteLater)
# connect its signal to the update_image slot
self.worker2.ImageUpdate.connect(self.ImageUpdateSlot)
# start the thread
self.thread2.start()
def Label_update(self,acc_val):
self.ACC1_X.setText(str(acc_val))
print(str(acc_val))
def ImageUpdateSlot(self, Image):
self.vid.setPixmap(QPixmap.fromImage(Image))
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow"))
self.Title.setText(_translate("MainWindow", "TEST"))
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
MainWindow = QtWidgets.QMainWindow()
ui = Ui_MainWindow()
ui.setupUi(MainWindow)
MainWindow.show()
sys.exit(app.exec_())