0

I am new and have been fighting this problem for a few days. I have a pyqt5 GUI with three classes (A, B, C). Classes A(MainFrame) and B(CameraParameters) are GUI windows, and C(Video_Thread) is Thread. You can activate Thread (C) from the A window. Also, window B can be opened from window A and has sliders.

Thread emits a signal(cv2 image) and translates to a label on window A.

Window B slides suppose to control camera Properties(cv2.VideoCapture(cv2.CAP_PROP)).

I am sending a signal from the Thread(C) to the Window(B) and making a slot that suppose to set a Slider value, but nothing is happening.

class MainFrame(QMainWindow):

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

    self.Video_Feed_is_Running = False
    # Loading UI

    uic.loadUi("MainFrame.ui", self)

    # Remove maximize button to prevent crushing
    self.setWindowFlags(Qt.WindowCloseButtonHint | Qt.WindowMinimizeButtonHint)

    # Define Widgets
    self.Video_Feed = self.findChild(QLabel, 'Video_Feed')
    self.Case_Name = self.findChild(QLineEdit, "Case_Name")
    self.Pictures_List = self.findChild(QListWidget, "Pictures_List")
    self.Start_Video = self.findChild(QAction, 'actionStart_Video')
    self.Start_Video.setShortcut('Shift+S')
    self.Stop_Video = self.findChild(QAction, 'actionStop_Video')
    self.Stop_Video.setShortcut('Shift+F')
    self.Take_a_Picture = self.findChild(QAction, 'actionTake_a_picture')
    self.Take_a_Timed_Picture = self.findChild(QAction, 'actionTake_a_timed_picture')
    self.Camera_Properties = self.findChild(QAction, 'actionProperties')

    # Initializing Video

    self.Start_Video.triggered.connect(self.Start_Video_Clicked)
    self.Stop_Video.triggered.connect(self.Stop_Video_Clicked)
    self.Camera_Properties.triggered.connect(self.Camera_Properties_Clicked)

def Video_Feed_Update(self, Image):
    self.Video_Feed.setPixmap(QPixmap.fromImage(Image))

def Start_Video_Clicked(self):
    self.Video_Thread = Video_Thread()
    self.Video_Thread.start()
    self.Video_Thread.ImageUpdate.connect(self.Video_Feed_Update)
    self.Video_Feed_is_Running = True

def Stop_Video_Clicked(self):
    self.Video_Thread.stop_video()
    self.Video_Feed.setText("Your video starts here")
    self.Video_Feed_is_Running = False

def Camera_Properties_Clicked(self):
    if self.Video_Feed_is_Running:
        self.CP = CameraParameters()
        self.CP.show()
    else:
        print("No video feed")


class Video_Thread(QThread):
# Recieving signal
ImageUpdate = pyqtSignal(QImage)
Exposure = pyqtSignal(int)

def __init__(self):
    super(Video_Thread, self).__init__()
    self.ThreadActive = True
    self.Capture = cv2.VideoCapture(1, cv2.CAP_DSHOW)
    self.Capture.set(cv2.CAP_PROP_EXPOSURE,-10)
    self.Capture.set(3, 1920)
    self.Capture.set(4, 1080)
    self.Exposure.emit(int(self.Capture.get(cv2.CAP_PROP_EXPOSURE)))

def run(self):

    while self.ThreadActive:
        ret, frame = self.Capture.read()
        if ret:
            image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            # Converting Video into QT5 readable format
            qt_video_format = QImage(image.data, image.shape[1], image.shape[0], QImage.Format_RGB888)
            qt_picture = qt_video_format.scaled(1280, 720, Qt.KeepAspectRatio)
            self.ImageUpdate.emit(qt_picture)

def stop_video(self):
    self.ThreadActive = False
    self.Capture.release()


class CameraParameters(QDialog):
def __init__(self):
    super().__init__()
    uic.loadUi('Cam_Parameters.ui', self)
    # Define Widgets
    self.Video_Thread=Video_Thread()
    # Sliders
    self.Exposure_Slider = self.findChild(QSlider, 'ExposureSlider')
    self.Exposure_Slider.setRange(-10, 10)
    # Sliders values
    self.Exposure_Value = self.findChild(QLabel, 'Exposure_Value')
    
    self.Video_Thread.Exposure.connect(self.Exposure_set)


def Exposure_set(self, value):
    self.Exposure_Slider.setValue(value)
    self.Exposure_Value.setText(str(value))

if __name__ == "__main__":
App = QApplication(sys.argv)
Root = MainFrame()
Root.show()
sys.exit(App.exec())

Thank you.

Helix05
  • 13
  • 3

1 Answers1

0

I can't run your code due to not having your ui file but straight away it seems like you're trying to run a QThread object directly. Instead what you should do is create a worker QObject and and seperate QThread, and then use moveToThread() to run the worker on the thread. So your Video_Thread() class would be a QObject, and you don't need to subclass QThread. Here is a snippet of my code to demonstrate:

def apply_calculation(self, selected_calc, selected_holes):
        
        # Step 1: Create a QThread object
        self.thread = QThread()
        # Step 2: Create a worker object
        self.worker = ApplyCalculation(selected_holes, selected_calc)
        # Step 3: Move worker to the thread
        self.worker.moveToThread(self.thread)
        # Step 4: Connect signals and slots
        self.thread.started.connect(self.worker.apply_calculation_handler)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.worker.progress.connect(self.report_progress)
        # Step 5: Start the thread
        self.thread.start()

Here you can see my connection for the progress report, which updates a progress bar in the gui.

Dharman
  • 30,962
  • 25
  • 85
  • 135
Alex
  • 172
  • 9
  • Thank you, Alex and my apology for the late response. I have tried your approach, but it did not solve my issue. Instead, of editing the existing question I made a new one and attached UI files and some screenshots. https://stackoverflow.com/questions/71368379/changing-qthread-variable-from-a-sub-window. I have tried different ways to make sliders to send signals to the thread but so far no luck. – Helix05 Mar 06 '22 at 17:15