I have been trying to use QThread and Signals together. Having a secondary class, moved to a new thread thanks to QThread, that can communicate with the main thread through the Signals/Slots system.
Here is a basic usage example, adapted to PyQt5 from this SO question, where I corrected the suggested problem (connect the start signal of simulThread), and also moved everything out of any GUI component :
import time, sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class SimulRunner(QObject):
'Object that will be run in a secondary thread'
stepIncreased = pyqtSignal(int)
nextStep = pyqtSignal()
def __init__(self):
super(SimulRunner, self).__init__()
self._step = 0
self._isRunning = True
self.nextStep.connect(self.longRunning)
@pyqtSlot()
def longRunning(self):
print("Thread running ? " + str(self._isRunning))
if self._isRunning == True: # A simple while loop would
# prevent the Qt event loop to
# treat the stop signal
# Increase counter
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.5)
# Trying to give the control back to the event loop for a
# moment, hoping that Stop signals will be treated before
# the recursive call
self.nextStep.emit()
# This alternative doesn't change the 'stop' button
# problem
'self.longRunning()'
@pyqtSlot()
def stop(self):
print("Stopping thread")
self._isRunning = False
class SimulationUi(QObject):
'Main thread'
startSignal = pyqtSignal()
stopSignal = pyqtSignal()
def __init__(self):
super(SimulationUi, self).__init__()
# Setup counter
self.counter = 0
# Create thread and connect start signals
self.simulRunner = SimulRunner()
self.simulThread = QThread()
self.simulRunner.moveToThread(self.simulThread)
# Connect with Thread
self.startSignal.connect(self.simulThread.start) # Does work
self.simulThread.started.connect(self.simulRunner.longRunning) # Does work
# Connect with runner Object
self.simulRunner.stepIncreased.connect(self.showProgress) # Only works with 'app = QApplication(sys.argv)
self.stopSignal.connect(self.simulRunner.stop) # Does NOT work
@pyqtSlot(int)
def showProgress(self, integer):
print(integer)
def start(self):
self.startSignal.emit()
def stop(self):
self.stopSignal.emit()
if __name__ == '__main__':
app = QApplication(sys.argv) # This single line is needed for the
# 'showProgress' callback to work
simul = SimulationUi()
simul.start()
input("Hit 'Return' a first time to stop the counter.\n")
simul.stop()
input("Now the thread should have stop. Return to terminate.\n")
The results are:
startSignal effectively starts the thread and the counter.
stepIncreased signal from the secondary thread is effectively caught by showProgress() in the main thread (but only if the line app = QApplication(sys.argv) is present ).
stopSignal from main thread is never caught by stop() in the secondary thread, even if with the workarounds to a simple while loop when counting (see comments in the code).
My questions are:
Why do I need to create an app out of nowhere for Secondary to Main thread signals to work ?
Why does not the opposite way work too ? (Main to Secondary)
app = QApplication(... is needed apparently since QEventLoop: Cannot be used without QApplication and QEventLoop "provides a means of entering and leaving an event loop" according to the documentation.
I have been trying to use QThread and Signals together. Having a secondary class, moved to a new thread thanks to QThread, that can communicate with the main thread through the Signals/Slots system. Here is a basic usage example, adapted to PyQt5 from this SO question, where I corrected the suggested problem (connect the
start
signal ofsimulThread
), and also moved everything out of any GUI component :The results are:
startSignal
effectively starts the thread and the counter.stepIncreased
signal from the secondary thread is effectively caught byshowProgress()
in the main thread (but only if the lineapp = QApplication(sys.argv)
is present ).stopSignal
from main thread is never caught bystop()
in the secondary thread, even if with the workarounds to a simplewhile
loop when counting (see comments in the code).My questions are:
Thank you for the help.