How to stop a QThread from the GUI
pyqt, pyqt4, python, qthread
Solution
I found out that my original question was actually two questions in one: in order to stop a secondary thread from the main one, you need two things:
Be able to communicate from the main thread down to the secondary thread
Send the proper signal to stop the thread
I haven't been able to solve (2), but I figured out how to solve (1), which gave me a workaround to my original problem. Instead of stopping the thread, I can stop the thread's processing (the `longRunning()` method)
The problem is that a a secondary thread can only respond to signals if it runs its own event loop. A regular Qthread (which is what my code used) does not. It is easy enough, though, to subclass QThread to that effect:
class MyThread(QThread):
def run(self):
self.exec_()
and used `self.simulThread = MyThread()` in my code instead of the original `self.simulThread = Qthread()`. This ensures that the secondary thread runs an event loop. That was not enough, though. The `longRunning()` method needs to have a chance to actually process the event coming down from the main thread. With the help of this SO answer I figured out that the simple addition of a `QApplication.processEvent()` in the `longRunning()` method gave the secondary thread such a chance. I can now stop the processing carried out in the secondary thread, even though I haven't figured out how to stop the thread itself.
To wrap up. My longRunning method now looks like this:
def longRunning(self):
while self._step < self._maxSteps and self._isRunning == True:
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.1)
QApplication.processEvents()
and my GUI thread has these three lines that do the job (in addition to the QThread subclass listed above):
self.simulThread = MyThread()
self.simulRunner.moveToThread(self.simulThread)
self.stopButton.clicked.connect(self.simulRunner.stop)
Comments are welcome!
Problem
This is a follow up question to a previous one I posted earlier. The problem is how to stop (terminate|quit|exit) a QThread from the GUI when using the recommended method of NOT subclassing Qthread, but rather vreating a QObject and then moving it to a QThread. Below if a working example. I can start the GUI and the Qthread and I can have the latter update the GUI. However, I cannot stop it. I tried several methods for qthread (quit(), exit(), and even terminate()) to no avail. Help greatly appreciated. Here is the complete code: ``` import time, sys from PyQt4.QtCore import * from PyQt4.QtGui import * class SimulRunner(QObject): 'Object managing the simulation' stepIncreased = pyqtSignal(int, name = 'stepIncreased') def __init__(self): super(SimulRunner, self).__init__() self._step = 0 self._isRunning = True self._maxSteps = 20 def longRunning(self): while self._step < self._maxSteps and self._isRunning == True: self._step += 1 self.stepIncreased.emit(self._step) time.sleep(0.1) def stop(self): self._isRunning = False class SimulationUi(QDialog): 'PyQt interface' def __init__(self): super(SimulationUi, self).__init__() self.goButton = QPushButton('Go') self.stopButton = QPushButton('Stop') self.currentStep = QSpinBox() self.layout = QHBoxLayout() self.layout.addWidget(self.goButton) self.layout.addWidget(self.stopButton) self.layout.addWidget(self.currentStep) self.setLayout(self.layout) self.simulRunner = SimulRunner() self.simulThread = QThread() self.simulRunner.moveToThread(self.simulThread) self.simulRunner.stepIncreased.connect(self.currentStep.setValue) self.stopButton.clicked.connect(simulThread.qui) # also tried exit() and terminate() # also tried the following (didn't work) # self.stopButton.clicked.connect(self.simulRunner.stop) self.goButton.clicked.connect(self.simulThread.start) self.simulThread.started.connect(self.simulRunner.longRunning) self.simulRunner.stepIncreased.connect(self.current.step.setValue) if __name__ == '__main__': app = QApplication(sys.argv) simul = SimulationUi() simul.show() sys.exit(app.exec_()) ```