how to pass data(variable) from QMainWindow to Qthread?
I am trying to create a save function that takes user's input but the function itself is in QMainWindow class and savepath in Qthread class. How do I emit a signal from QMainWindow to Qthread to replace a default savepath? I've tried to do something similar in topic 33300818 How to pass data between threads in PyQt5? but I didn't get results
Here's a part of the code
from PyQt5 import QtGui, QtWidgets, QtCore
from PyQt5.QtWidgets import QWidget, QApplication, QLabel, QGridLayout, QAction, QMainWindow, QMessageBox, QStatusBar, QDesktopWidget, QFileDialog, QToolBar, QTextEdit
from PyQt5.QtGui import QPixmap, QIcon, QFont, QTextCursor
from PyQt5.QtCore import pyqtSignal, Qt, QThread
import sys
import os
import cv2
import time
import numpy as np
from datetime import datetime
VERSION = "v1.00"
IMG_SIZE = 640, 480 # 640,480 or 1280,720 or 1920,1080
CAP_API = cv2.CAP_DSHOW
EXPOSURE = 0
TEXT_FONT = QFont("Courier", 10)
camera_num = 1
timestr = time.strftime("%d-%b-%Y-%H_%M_%S")
save_vpath = ''
save_seq = 0
full_save_vpath = os.path.join(save_vpath, "%04d-%s.mkv" % (
save_seq,
timestr))
CurrUser = os.environ.get('USERNAME')
class VideoThread(QThread):
change_pixmap_signal = pyqtSignal(np.ndarray)
def __init__(self, *args, **kwargs):
super().__init__()
self._run_flag = True
def run(self):
total_frames = 0
self.ThreadActive = True
self.cap = cv2.VideoCapture(camera_num-1 + CAP_API)
self.cap.set(cv2.CAP_PROP_FRAME_WIDTH, IMG_SIZE[0])
self.cap.set(cv2.CAP_PROP_FRAME_HEIGHT, IMG_SIZE[1])
if EXPOSURE:
self.cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 0)
self.cap.set(cv2.CAP_PROP_EXPOSURE, EXPOSURE)
else:
self.cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1)
prev_frame_time = 0
new_frame_time = 0
if full_save_vpath:
width = IMG_SIZE[0]
height = IMG_SIZE[1]
self.fourcc = cv2.VideoWriter_fourcc(*'XVID')
fps = 30
self.out = cv2.VideoWriter(full_save_vpath, self.fourcc, fps, (width, height))
while self.ThreadActive:
ret, frame = self.cap.read()
if not ret:
break
if ret:
height, width, _ = frame.shape
rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
new_frame_time = time.time()
fps_count = 1 / (new_frame_time - prev_frame_time)
prev_frame_time = new_frame_time
fps_count = int(fps_count)
fps_count = str(fps_count)
self.change_pixmap_signal.emit(frame)
if full_save_vpath:
self.out.write(frame)
total_frames += 1
self.cap.release()
def stop(self):
self._run_flag = False
self.wait()
if full_save_vpath:
self.out.release()
class MyWindow(QMainWindow):
text_update = pyqtSignal(str)
def __init__(self):
super(MyWindow, self).__init__()
self.vthread = VideoThread(self)
self.setWindowTitle(VERSION)
self.setWindowIcon(QIcon('Icon/count.png'))
cent = QDesktopWidget().availableGeometry().center() # Finds the center of the screen
self.frameGeometry().moveCenter(cent)
self.widget = QWidget()
self.layout = QGridLayout(self.widget)
self.display_width = 1280
self.display_height = 720
self.image_label = QLabel(self)
self.image_label.resize(self.display_width, self.display_height)
self.image_label.setAlignment(Qt.AlignCenter)
self.layout.addWidget(self.image_label)
self.setCentralWidget(self.widget)
#create statusbar
self.status = QStatusBar()
self.status.setStyleSheet("background : lightgray;")
self.setStatusBar(self.status) # Adding status bar to the main window
#create mainmenu
self.statusBar()
menu_Bar = self.menuBar()
file_menu = menu_Bar.addMenu('&File')
play_menu = menu_Bar.addMenu('&Play')
#create exit action
exitAction = QAction(QIcon('Icon/exit.png'), '&Exit', self)
exitAction.setShortcut('Ctrl+Q')
exitAction.setStatusTip('Exit application')
exitAction.triggered.connect(self.close)
file_menu.addAction(exitAction)
#create save action
saveAction = QAction('Save as', self)
saveAction.setStatusTip("Change folder where v/o will be saved.")
saveAction.triggered.connect(self.change_folder)
file_menu.addAction(saveAction)
#create start action
self.startAction = QAction(QIcon('Icon/rec_start.png'), 'Start Feed', self)
self.startAction.setStatusTip("Start camera feed.")
self.startAction.triggered.connect(self.start_feed)
self.startAction.triggered.connect(self.start_inactive)
self.startAction.setEnabled(True)
play_menu.addAction(self.startAction)
#create stop action
self.stopAction = QAction(QIcon('Icon/rec_stop.png'), 'Stop Feed', self)
self.stopAction.setStatusTip("Stop camera feed.")
self.stopAction.triggered.connect(self.stop_feed)
self.stopAction.triggered.connect(self.hide_frame)
self.stopAction.triggered.connect(self.start_active)
self.stopAction.setEnabled(False)
play_menu.addAction(self.stopAction)
#create toolbar
self.toolbar = QToolBar('Toolbar')
self.addToolBar(self.toolbar)
self.toolbar.setMovable(False)
self.toolbar.addAction(exitAction)
self.toolbar.addAction(self.startAction)
self.toolbar.addAction(self.stopAction)
def update_image(self, img_label):
qt_img = self.convert_cv_qt(img_label)
self.image_label.setPixmap(qt_img)
def convert_cv_qt(self, frame):
rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
bytes_per_line = ch * w
convert_to_Qt_format = QtGui.QImage(rgb_image.data, w, h, bytes_per_line, QtGui.QImage.Format_RGB888)
return QPixmap.fromImage(convert_to_Qt_format)
def write(self, text):
self.text_update.emit(str(text))
def flush(self):
pass
# Append to text display
def append_text(self, text):
cur = self.textbox.textCursor() # Move cursor to end of text
cur.movePosition(QTextCursor.End)
s = str(text)
while s:
head,sep,s = s.partition("\n") # Split line at LF
cur.insertText(head) # Insert text at cursor
if sep: # New line if LF
cur.insertBlock()
self.textbox.setTextCursor(cur) # Update visible cursor
def start_feed(self):
self.stopAction.setEnabled(True)
self.thread = VideoThread()
self.image_label.setAlignment(Qt.AlignCenter)
#self.layout.addWidget(self.image_label)
self.thread.change_pixmap_signal.connect(self.update_image)
self.thread.start()
self.textbox = QTextEdit(self.widget)
self.textbox.setFont(TEXT_FONT)
self.textbox.setMaximumSize(640, 100)
self.text_update.connect(self.append_text)
sys.stdout = self
print(datetime.now())
self.layout.addWidget(self.textbox, 1, 0)
def start_inactive(self):
self.startAction.setEnabled(False)
def start_active(self):
self.startAction.setEnabled(True)
def stop_feed(self):
if self.thread.ThreadActive:
self.thread.change_pixmap_signal.disconnect()
self.text_update.disconnect()
self.thread.ThreadActive = False
else:
self.thread.terminate()
def hide_frame(self):
self.widget = QWidget()
self.layout = QGridLayout(self.widget)
self.display_width = 1280
self.display_height = 720
self.image_label = QLabel(self)
self.image_label.resize(self.display_width, self.display_height)
self.image_label.move(0, 0)
self.layout.addWidget(self.image_label)
self.setCentralWidget(self.widget)
def change_folder(self):
path = QFileDialog.getExistingDirectory(self, "video location", "")
if path:
self.chosen_path = os.path.join(path, "%04d-%s.mkv" % (save_seq, timestr)).replace(os.sep, '/')
self.save_seq = 0
print(self.chosen_path)
if __name__ == "__main__":
app = QApplication(sys.argv)
win = MyWindow()
win.show()
sys.exit(app.exec_())```