Как остановить QThread из GUI
Это следующий вопрос к предыдущему, который я опубликовал ранее. Проблема заключается в том, как остановить (завершить|выйти|выйти) QThread из GUI при использовании рекомендуемого метода не подкласса Qthread, а скорее создания QObject, а затем переместить его в QThread. Ниже приведен рабочий пример. Я могу запустить GUI и Qthread, и я могу иметь последнее обновление GUI. Однако я не могу остановить это. Я попробовал несколько методов для qthread (quit (), exit () и даже terminate ()), чтобы нет выгода. Помощь очень ценится.
вот полный код:
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_())
2 ответов
Я знаю ее давно, но я просто наткнулся на ту же проблему.
Я также искал подходящий способ сделать это. Наконец-то все стало просто. При выходе из приложения задача должна быть остановлена, а поток должен быть остановлен, вызывая его метод quit. См. Метод stop_thread на дно. И тебе нужно дождаться окончания нити. В противном случае вы получите QThread: уничтожено, пока поток все еще работает " сообщение при выходе.
(I также изменен мой код для использования pyside)
import time, sys
from PySide.QtCore import *
from PySide.QtGui import *
class Worker(QObject):
'Object managing the simulation'
stepIncreased = Signal(int)
def __init__(self):
super(Worker, self).__init__()
self._step = 0
self._isRunning = True
self._maxSteps = 20
def task(self):
if not self._isRunning:
self._isRunning = True
self._step = 0
while self._step < self._maxSteps and self._isRunning == True:
self._step += 1
self.stepIncreased.emit(self._step)
time.sleep(0.1)
print "finished..."
def stop(self):
self._isRunning = False
class SimulationUi(QDialog):
def __init__(self):
super(SimulationUi, self).__init__()
self.btnStart = QPushButton('Start')
self.btnStop = QPushButton('Stop')
self.currentStep = QSpinBox()
self.layout = QHBoxLayout()
self.layout.addWidget(self.btnStart)
self.layout.addWidget(self.btnStop)
self.layout.addWidget(self.currentStep)
self.setLayout(self.layout)
self.thread = QThread()
self.thread.start()
self.worker = Worker()
self.worker.moveToThread(self.thread)
self.worker.stepIncreased.connect(self.currentStep.setValue)
self.btnStop.clicked.connect(lambda: self.worker.stop())
self.btnStart.clicked.connect(self.worker.task)
self.finished.connect(self.stop_thread)
def stop_thread(self):
self.worker.stop()
self.thread.quit()
self.thread.wait()
if __name__ == '__main__':
app = QApplication(sys.argv)
simul = SimulationUi()
simul.show()
sys.exit(app.exec_())
я узнал, что мой первоначальный вопрос на самом деле был двумя вопросами в одном: чтобы остановить вторичный поток от основного, вам нужно две вещи:
уметь общаться с основным потоком вниз к вторичной нити
отправить правильный сигнал, чтобы остановить поток
Я не смог решить (2), но я понял, как решить (1), что дало мне обходной путь к моей первоначальной проблеме. Вместо того, чтобы остановить нить, я могу остановить потока обработка (the longRunning()
способ)
проблема в том, что вторичный поток может отвечать только на сигналы, если он запускает свой собственный цикл событий. Обычный Qthread (это мой код) не. Однако достаточно легко подкласс QThread для этого:
class MyThread(QThread):
def run(self):
self.exec_()
и использовать self.simulThread = MyThread()
в моем коде вместо оригинального self.simulThread = Qthread()
.
Это гарантирует, что вторичный поток выполняет цикл событий. Однако, это не достаточно,. The longRunning()
метод должен иметь возможность фактически обработать событие, исходящее из основного потока. С помощью это так ответ я понял, что простое добавление QApplication.processEvent()
на longRunning()
метод дал вторичному потоку такой шанс. Теперь я могу остановить обработка выполняется во вторичном потоке, хотя я не понял, как остановить поток себя.
завернуть. Мой метод longRunning теперь выглядит так:
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()
и мой поток GUI имеет эти три строки ,которые выполняют эту работу (в дополнение к подклассу QThread, перечисленному выше):
self.simulThread = MyThread()
self.simulRunner.moveToThread(self.simulThread)
self.stopButton.clicked.connect(self.simulRunner.stop)
комментарии приветствуются!