How to Use Multithreading
-
Hello Guys, I am currently making a interactive GUI for user where I have to display live video feed from camera and some serial data coming from Arduino. Currently the live video feed comes from my USB camera and I have to show this along with the data simultaneously. I have seen videos for Q Thread and Video Display using push Button.
My question is how can I achieve display the data and no delay video feed at the same time using multi-threading after pressing just a single button named 'VD Display Button'.
I am using pyqt5
-
@jsulm so what I want to do is I press a button after pressing that button it should go to the method named suppose 'abc'.
In method abc I need to perfrom continuous reading of data until stopped and at the same time update the display real time for the data that is coming.
here is the sample code:
#!/usr/bin/env python3import os, sys, time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QLibraryInfo, pyqtSignal, pyqtSlot, QUrl, QTimer, QTime, QDate, QThread
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow
from PyQt5.uic import loadUi
from PyQt5.QtGui import QImage
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentos.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QLibraryInfo.location(
QLibraryInfo.PluginsPath
)class Sample_UI(QDialog):
def init(self):
super(Sample_UI,self).init()
loadUi('Sample_Update.ui',self)self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('LOGIC_CONTROL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.testing) self.Save_Button.clicked.connect(self.save_data)
def logic(self):
import logic_build_library
self.abc=logic_build_library.class1()try: systat=self.abc.sys_status() if systat is not None: self.label_12.setStyleSheet('background-color: green; color: black;') else: self.label_12.setStyleSheet('background-color: red; color: black;') except Exception as e: self.label_12.setStyleSheet('background-color: red; color: black;') def showTime(self): currentTime = QTime.currentTime() today_date=QDate.currentDate() displayTxt = today_date.toString()+" "+currentTime.toString('hh:mm:ss') self.label_6.setText(displayTxt) def save_data(self): print('Data Saved!') login=Login() widget.setFixedWidth(360) widget.setFixedHeight(360) widget.addWidget(login) widget.setCurrentIndex(widget.currentIndex()+1)
How can I continuously fetch data and display it at the same time?
@vidyul let me chatgpt that for you:
To continuously fetch data and update the display in real-time, you can use a separate thread to fetch the data and emit a signal every time new data is available. The main thread can then connect a slot to this signal to update the UI. Here’s a simplified example:
class DataThread(QThread): data_signal = pyqtSignal(object) def run(self): while True: data = self.fetch_data() # replace with your data fetching logic self.data_signal.emit(data) time.sleep(1) # sleep for a while to prevent high CPU usage class ATE_UI(QDialog): def __init__(self): super(ATE_UI,self).__init__() loadUi('ATE_Update.ui',self) self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('Flight Mode: VTOL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.start_fetching_data) self.Save_Button.clicked.connect(self.save_data) self.data_thread = DataThread() self.data_thread.data_signal.connect(self.update_display) def start_fetching_data(self): self.data_thread.start() def update_display(self, data): # update your display with the new data here pass # ... rest of your code ...
In this example, pressing the Test_Button will start the DataThread, which fetches data in a loop until stopped. Every time new data is fetched, it emits a signal with the data, which is connected to the update_display slot in the main thread. This slot can then update the UI with the new data.
Please replace self.fetch_data() with your actual data fetching logic and implement the update_display method to update your UI with the new data. Also, don’t forget to handle stopping the thread when necessary. You might want to add a stop button and connect it to a method that calls self.data_thread.terminate(). Be aware that terminating threads can be dangerous if not handled properly, so it’s better to have a mechanism in your thread to stop it gracefully. For example, you can use a QMutex and a flag to check whether the thread should stop or continue fetching data. If the flag is set, the thread can finish its current iteration and then stop itself by returning from the run method. This way, you can avoid abruptly stopping the thread and potentially leaving resources in an inconsistent state.
Please note that this is a simplified example and might not cover all edge cases. Always make sure to handle exceptions and edge cases in your code to prevent crashes and ensure a smooth user experience. Also, keep in mind that updating the UI from a different thread is not safe, and you should always use signals and slots for communication between threads in Qt.
-
Hello Guys, I am currently making a interactive GUI for user where I have to display live video feed from camera and some serial data coming from Arduino. Currently the live video feed comes from my USB camera and I have to show this along with the data simultaneously. I have seen videos for Q Thread and Video Display using push Button.
My question is how can I achieve display the data and no delay video feed at the same time using multi-threading after pressing just a single button named 'VD Display Button'.
I am using pyqt5
@vidyul Not sure what exactly your question is.
If you think you really need more than one thread (do you?) then start a second thread where you retrieve the video frames and forward these frames via signals/slots to UI thread to show them (it is not allowed to manipulate UI from other threads!). For serial communication there is really no need for another threads - it is also asynchronous in Qt like all other stuff. -
@vidyul Not sure what exactly your question is.
If you think you really need more than one thread (do you?) then start a second thread where you retrieve the video frames and forward these frames via signals/slots to UI thread to show them (it is not allowed to manipulate UI from other threads!). For serial communication there is really no need for another threads - it is also asynchronous in Qt like all other stuff.@jsulm so what I want to do is I press a button after pressing that button it should go to the method named suppose 'abc'.
In method abc I need to perfrom continuous reading of data until stopped and at the same time update the display real time for the data that is coming.
here is the sample code:
#!/usr/bin/env python3import os, sys, time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QLibraryInfo, pyqtSignal, pyqtSlot, QUrl, QTimer, QTime, QDate, QThread
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow
from PyQt5.uic import loadUi
from PyQt5.QtGui import QImage
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentos.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QLibraryInfo.location(
QLibraryInfo.PluginsPath
)class Sample_UI(QDialog):
def init(self):
super(Sample_UI,self).init()
loadUi('Sample_Update.ui',self)self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('LOGIC_CONTROL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.testing) self.Save_Button.clicked.connect(self.save_data)
def logic(self):
import logic_build_library
self.abc=logic_build_library.class1()try: systat=self.abc.sys_status() if systat is not None: self.label_12.setStyleSheet('background-color: green; color: black;') else: self.label_12.setStyleSheet('background-color: red; color: black;') except Exception as e: self.label_12.setStyleSheet('background-color: red; color: black;') def showTime(self): currentTime = QTime.currentTime() today_date=QDate.currentDate() displayTxt = today_date.toString()+" "+currentTime.toString('hh:mm:ss') self.label_6.setText(displayTxt) def save_data(self): print('Data Saved!') login=Login() widget.setFixedWidth(360) widget.setFixedHeight(360) widget.addWidget(login) widget.setCurrentIndex(widget.currentIndex()+1)
How can I continuously fetch data and display it at the same time?
-
@jsulm so what I want to do is I press a button after pressing that button it should go to the method named suppose 'abc'.
In method abc I need to perfrom continuous reading of data until stopped and at the same time update the display real time for the data that is coming.
here is the sample code:
#!/usr/bin/env python3import os, sys, time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QLibraryInfo, pyqtSignal, pyqtSlot, QUrl, QTimer, QTime, QDate, QThread
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow
from PyQt5.uic import loadUi
from PyQt5.QtGui import QImage
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentos.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QLibraryInfo.location(
QLibraryInfo.PluginsPath
)class Sample_UI(QDialog):
def init(self):
super(Sample_UI,self).init()
loadUi('Sample_Update.ui',self)self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('LOGIC_CONTROL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.testing) self.Save_Button.clicked.connect(self.save_data)
def logic(self):
import logic_build_library
self.abc=logic_build_library.class1()try: systat=self.abc.sys_status() if systat is not None: self.label_12.setStyleSheet('background-color: green; color: black;') else: self.label_12.setStyleSheet('background-color: red; color: black;') except Exception as e: self.label_12.setStyleSheet('background-color: red; color: black;') def showTime(self): currentTime = QTime.currentTime() today_date=QDate.currentDate() displayTxt = today_date.toString()+" "+currentTime.toString('hh:mm:ss') self.label_6.setText(displayTxt) def save_data(self): print('Data Saved!') login=Login() widget.setFixedWidth(360) widget.setFixedHeight(360) widget.addWidget(login) widget.setCurrentIndex(widget.currentIndex()+1)
How can I continuously fetch data and display it at the same time?
@vidyul said in How to Use Multithreading:
How can I continuously fetch data and display it at the same time?
I have no idea how you fetch the data - you did not explain what camera and how you're accessing it. And regarding displaying: I already wrote that you can pass the data from the camera fetching thread to the UI thread using signals/slots.
-
@jsulm so what I want to do is I press a button after pressing that button it should go to the method named suppose 'abc'.
In method abc I need to perfrom continuous reading of data until stopped and at the same time update the display real time for the data that is coming.
here is the sample code:
#!/usr/bin/env python3import os, sys, time
from PyQt5 import QtWidgets, QtCore
from PyQt5.QtCore import QLibraryInfo, pyqtSignal, pyqtSlot, QUrl, QTimer, QTime, QDate, QThread
from PyQt5.QtWidgets import QDialog, QApplication, QMainWindow
from PyQt5.uic import loadUi
from PyQt5.QtGui import QImage
from PyQt5.QtMultimedia import QMediaPlayer, QMediaContentos.environ["QT_QPA_PLATFORM_PLUGIN_PATH"] = QLibraryInfo.location(
QLibraryInfo.PluginsPath
)class Sample_UI(QDialog):
def init(self):
super(Sample_UI,self).init()
loadUi('Sample_Update.ui',self)self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('LOGIC_CONTROL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.testing) self.Save_Button.clicked.connect(self.save_data)
def logic(self):
import logic_build_library
self.abc=logic_build_library.class1()try: systat=self.abc.sys_status() if systat is not None: self.label_12.setStyleSheet('background-color: green; color: black;') else: self.label_12.setStyleSheet('background-color: red; color: black;') except Exception as e: self.label_12.setStyleSheet('background-color: red; color: black;') def showTime(self): currentTime = QTime.currentTime() today_date=QDate.currentDate() displayTxt = today_date.toString()+" "+currentTime.toString('hh:mm:ss') self.label_6.setText(displayTxt) def save_data(self): print('Data Saved!') login=Login() widget.setFixedWidth(360) widget.setFixedHeight(360) widget.addWidget(login) widget.setCurrentIndex(widget.currentIndex()+1)
How can I continuously fetch data and display it at the same time?
@vidyul let me chatgpt that for you:
To continuously fetch data and update the display in real-time, you can use a separate thread to fetch the data and emit a signal every time new data is available. The main thread can then connect a slot to this signal to update the UI. Here’s a simplified example:
class DataThread(QThread): data_signal = pyqtSignal(object) def run(self): while True: data = self.fetch_data() # replace with your data fetching logic self.data_signal.emit(data) time.sleep(1) # sleep for a while to prevent high CPU usage class ATE_UI(QDialog): def __init__(self): super(ATE_UI,self).__init__() loadUi('ATE_Update.ui',self) self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('Flight Mode: VTOL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.start_fetching_data) self.Save_Button.clicked.connect(self.save_data) self.data_thread = DataThread() self.data_thread.data_signal.connect(self.update_display) def start_fetching_data(self): self.data_thread.start() def update_display(self, data): # update your display with the new data here pass # ... rest of your code ...
In this example, pressing the Test_Button will start the DataThread, which fetches data in a loop until stopped. Every time new data is fetched, it emits a signal with the data, which is connected to the update_display slot in the main thread. This slot can then update the UI with the new data.
Please replace self.fetch_data() with your actual data fetching logic and implement the update_display method to update your UI with the new data. Also, don’t forget to handle stopping the thread when necessary. You might want to add a stop button and connect it to a method that calls self.data_thread.terminate(). Be aware that terminating threads can be dangerous if not handled properly, so it’s better to have a mechanism in your thread to stop it gracefully. For example, you can use a QMutex and a flag to check whether the thread should stop or continue fetching data. If the flag is set, the thread can finish its current iteration and then stop itself by returning from the run method. This way, you can avoid abruptly stopping the thread and potentially leaving resources in an inconsistent state.
Please note that this is a simplified example and might not cover all edge cases. Always make sure to handle exceptions and edge cases in your code to prevent crashes and ensure a smooth user experience. Also, keep in mind that updating the UI from a different thread is not safe, and you should always use signals and slots for communication between threads in Qt.
-
@vidyul let me chatgpt that for you:
To continuously fetch data and update the display in real-time, you can use a separate thread to fetch the data and emit a signal every time new data is available. The main thread can then connect a slot to this signal to update the UI. Here’s a simplified example:
class DataThread(QThread): data_signal = pyqtSignal(object) def run(self): while True: data = self.fetch_data() # replace with your data fetching logic self.data_signal.emit(data) time.sleep(1) # sleep for a while to prevent high CPU usage class ATE_UI(QDialog): def __init__(self): super(ATE_UI,self).__init__() loadUi('ATE_Update.ui',self) self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('Flight Mode: VTOL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.start_fetching_data) self.Save_Button.clicked.connect(self.save_data) self.data_thread = DataThread() self.data_thread.data_signal.connect(self.update_display) def start_fetching_data(self): self.data_thread.start() def update_display(self, data): # update your display with the new data here pass # ... rest of your code ...
In this example, pressing the Test_Button will start the DataThread, which fetches data in a loop until stopped. Every time new data is fetched, it emits a signal with the data, which is connected to the update_display slot in the main thread. This slot can then update the UI with the new data.
Please replace self.fetch_data() with your actual data fetching logic and implement the update_display method to update your UI with the new data. Also, don’t forget to handle stopping the thread when necessary. You might want to add a stop button and connect it to a method that calls self.data_thread.terminate(). Be aware that terminating threads can be dangerous if not handled properly, so it’s better to have a mechanism in your thread to stop it gracefully. For example, you can use a QMutex and a flag to check whether the thread should stop or continue fetching data. If the flag is set, the thread can finish its current iteration and then stop itself by returning from the run method. This way, you can avoid abruptly stopping the thread and potentially leaving resources in an inconsistent state.
Please note that this is a simplified example and might not cover all edge cases. Always make sure to handle exceptions and edge cases in your code to prevent crashes and ensure a smooth user experience. Also, keep in mind that updating the UI from a different thread is not safe, and you should always use signals and slots for communication between threads in Qt.
-
-
@vidyul let me chatgpt that for you:
To continuously fetch data and update the display in real-time, you can use a separate thread to fetch the data and emit a signal every time new data is available. The main thread can then connect a slot to this signal to update the UI. Here’s a simplified example:
class DataThread(QThread): data_signal = pyqtSignal(object) def run(self): while True: data = self.fetch_data() # replace with your data fetching logic self.data_signal.emit(data) time.sleep(1) # sleep for a while to prevent high CPU usage class ATE_UI(QDialog): def __init__(self): super(ATE_UI,self).__init__() loadUi('ATE_Update.ui',self) self.Reports_Table.setColumnWidth(0,250) self.label_4.setText('Flight Mode: VTOL') timer=QTimer(self) timer.timeout.connect(self.showTime) timer.start(1) self.Test_Button.clicked.connect(self.start_fetching_data) self.Save_Button.clicked.connect(self.save_data) self.data_thread = DataThread() self.data_thread.data_signal.connect(self.update_display) def start_fetching_data(self): self.data_thread.start() def update_display(self, data): # update your display with the new data here pass # ... rest of your code ...
In this example, pressing the Test_Button will start the DataThread, which fetches data in a loop until stopped. Every time new data is fetched, it emits a signal with the data, which is connected to the update_display slot in the main thread. This slot can then update the UI with the new data.
Please replace self.fetch_data() with your actual data fetching logic and implement the update_display method to update your UI with the new data. Also, don’t forget to handle stopping the thread when necessary. You might want to add a stop button and connect it to a method that calls self.data_thread.terminate(). Be aware that terminating threads can be dangerous if not handled properly, so it’s better to have a mechanism in your thread to stop it gracefully. For example, you can use a QMutex and a flag to check whether the thread should stop or continue fetching data. If the flag is set, the thread can finish its current iteration and then stop itself by returning from the run method. This way, you can avoid abruptly stopping the thread and potentially leaving resources in an inconsistent state.
Please note that this is a simplified example and might not cover all edge cases. Always make sure to handle exceptions and edge cases in your code to prevent crashes and ensure a smooth user experience. Also, keep in mind that updating the UI from a different thread is not safe, and you should always use signals and slots for communication between threads in Qt.
-
@J-Hilk I have marked it as correct answer. I just wanted to know it for my knowledge that Can I have more than 1 worker class inherited from Q Thread? And How can I achieve that? It can be useful for me in the future.
@vidyul said in How to Use Multithreading:
Can I have more than 1 worker class inherited from Q Thread?
Sure, each of the worker runs then in its own thread.
"And How can I achieve that?" - in the same way you create one worker. -
@vidyul said in How to Use Multithreading:
Can I have more than 1 worker class inherited from Q Thread?
Sure, each of the worker runs then in its own thread.
"And How can I achieve that?" - in the same way you create one worker.@jsulm
@J-Hilk
Thank you for that info. I am currently facing an issue with the QThread you suggested.
After I finish with my task I am clicking a button and then going back to login page, but in the background the qthread is still running and printing the output. How should I end that thread when pressed the stop button and again use it when I press the button to start the process. -
@jsulm
@J-Hilk
Thank you for that info. I am currently facing an issue with the QThread you suggested.
After I finish with my task I am clicking a button and then going back to login page, but in the background the qthread is still running and printing the output. How should I end that thread when pressed the stop button and again use it when I press the button to start the process. -
@vidyul usually you call quit() on the thread. Doesn't necessarily work, depends on what you're doing inside the thread. If there's no event loop running, but something like an infinite while loop. You'll have to quit that first.
-
@J-Hilk Yes, so in the def run there is a while True running. Will I have to pass the button(s) as an object when I am creating an instance of the DataThread class?
Or I need to do something else?
@vidyul I'm not an expert in Python, but I assume there are equivalents to Atomics and or mutex? You need to check that variable every so often inside the loop and exit the loop when the condition is set.
Let me ask the AI to whip up an example.
-
@vidyul I'm not an expert in Python, but I assume there are equivalents to Atomics and or mutex? You need to check that variable every so often inside the loop and exit the loop when the condition is set.
Let me ask the AI to whip up an example.
@J-Hilk here you go:
import sys import time from PyQt5.QtCore import Qt, QThread, QTimer, QObject, QMutex, pyqtSignal from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget class Worker(QObject): finished = pyqtSignal() def __init__(self, mutex): super().__init__() self.mutex = mutex self.stop_flag = False def run_long_task(self): while not self.stop_flag: # Simulate some work time.sleep(1) print("Worker thread: Doing some work...") self.finished.emit() class Window(QMainWindow): def __init__(self): super().__init__() self.clicksCount = 0 self.setup_ui() def setup_ui(self): self.setWindowTitle("Thread Example") self.resize(300, 150) self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) # Create widgets self.clicksLabel = QLabel("Counting: 0 clicks", self) self.clicksLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.countBtn = QPushButton("Click me!", self) self.countBtn.clicked.connect(self.count_clicks) self.longRunningBtn = QPushButton("Long-Running Task!", self) self.longRunningBtn.clicked.connect(self.run_long_task) # Set layout layout = QVBoxLayout() layout.addWidget(self.clicksLabel) layout.addWidget(self.countBtn) layout.addStretch() layout.addWidget(self.longRunningBtn) self.centralWidget.setLayout(layout) def count_clicks(self): self.clicksCount += 1 self.clicksLabel.setText(f"Counting: {self.clicksCount} clicks") def run_long_task(self): mutex = QMutex() worker = Worker(mutex) def stop_worker(): with mutex: worker.stop_flag = True # Connect the worker's finished signal to stop the worker worker.finished.connect(stop_worker) # Start the worker thread thread = QThread() worker.moveToThread(thread) thread.started.connect(worker.run_long_task) thread.start() if __name__ == "__main__": app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec_())
-
@vidyul I'm not an expert in Python, but I assume there are equivalents to Atomics and or mutex? You need to check that variable every so often inside the loop and exit the loop when the condition is set.
Let me ask the AI to whip up an example.
-
@J-Hilk here you go:
import sys import time from PyQt5.QtCore import Qt, QThread, QTimer, QObject, QMutex, pyqtSignal from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton, QVBoxLayout, QWidget class Worker(QObject): finished = pyqtSignal() def __init__(self, mutex): super().__init__() self.mutex = mutex self.stop_flag = False def run_long_task(self): while not self.stop_flag: # Simulate some work time.sleep(1) print("Worker thread: Doing some work...") self.finished.emit() class Window(QMainWindow): def __init__(self): super().__init__() self.clicksCount = 0 self.setup_ui() def setup_ui(self): self.setWindowTitle("Thread Example") self.resize(300, 150) self.centralWidget = QWidget() self.setCentralWidget(self.centralWidget) # Create widgets self.clicksLabel = QLabel("Counting: 0 clicks", self) self.clicksLabel.setAlignment(Qt.AlignHCenter | Qt.AlignVCenter) self.countBtn = QPushButton("Click me!", self) self.countBtn.clicked.connect(self.count_clicks) self.longRunningBtn = QPushButton("Long-Running Task!", self) self.longRunningBtn.clicked.connect(self.run_long_task) # Set layout layout = QVBoxLayout() layout.addWidget(self.clicksLabel) layout.addWidget(self.countBtn) layout.addStretch() layout.addWidget(self.longRunningBtn) self.centralWidget.setLayout(layout) def count_clicks(self): self.clicksCount += 1 self.clicksLabel.setText(f"Counting: {self.clicksCount} clicks") def run_long_task(self): mutex = QMutex() worker = Worker(mutex) def stop_worker(): with mutex: worker.stop_flag = True # Connect the worker's finished signal to stop the worker worker.finished.connect(stop_worker) # Start the worker thread thread = QThread() worker.moveToThread(thread) thread.started.connect(worker.run_long_task) thread.start() if __name__ == "__main__": app = QApplication(sys.argv) win = Window() win.show() sys.exit(app.exec_())
@J-Hilk
So the current main.py file is:
Now I want to know where should I implement this part:
def run_long_task(self):
mutex = QMutex()
worker = Worker(mutex)def stop_worker(): with mutex: worker.stop_flag = True # Connect the worker's finished signal to stop the worker worker.finished.connect(stop_worker)
because I tried but it was not working. It prompt to force close the UI.
@J-Hilk