'QTreading implementation for two different functions - PyQT5
I've been trying to implement multithreading on PyQT5 using QThreads. I want to display a video and update a set of labels at the same time(I used a counter as an example). From my research I found different ways to implement QThreads, it was recommended to use the following method instead of instantiating QTread and modifying run method, so I followed that advice. Here is my reduced code:
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_())
When I run it I get the following error:
1
2
QThread: Destroyed while thread is still running
Aborted (core dumped)
WHat's the best way to implement it, and can normal threads be used instead of QThreads in this case?
Thank you
Solution 1:[1]
I figured it out, for some reason I defined worker2 inside of Label_update by mistake, I just moved Label_update method down and followed the comment of musicanante and now its working. here is the full working code if anyone is interested.
############################# 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.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_())
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 | Isra |
