如何从GUI停止QThread
这是对之前发布的前一个问题的跟进问题。 问题是如何在使用NOT子类化Qthread的推荐方法时停止(终止|退出|退出)QThread中的QThread,而是创建一个QObject,然后将其移至QThread。下面是一个工作示例。我可以启动GUI和Qthread,我可以让后者更新GUI。但是,我无法阻止它。我尝试了几种qthread(quit(),exit(),甚至terminate())方法无济于事。 非常感谢。如何从GUI停止QThread
下面是完整的代码:
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),但我想通了,如何解决(1),这给了我一个解决方法,我原来的问题。相反,停止线程的,我可以停止线程的处理(该longRunning()
法)
的问题是,如果它运行其自己的事件循环辅助线程只能对信号做出响应。一个普通的Qthread(这是我的代码使用的)没有。这是很容易的,但是,子类的QThread该效果:
class MyThread(QThread):
def run(self):
self.exec_()
,并在我的代码,而不是原始self.simulThread = Qthread()
使用self.simulThread = MyThread()
。 这可确保辅助线程运行事件循环。虽然这还不够。 longRunning()
方法需要有机会真正处理来自主线程的事件。在this SO answer的帮助下,我发现在longRunning()
方法中简单添加QApplication.processEvent()
就给了次要线程这样一个机会。我现在可以停止在辅助线程中执行处理,尽管我还没有想出如何停止线程本身。
结束。我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)
评论,欢迎!
我遇到了很多问题,然后创建了我自己的解决方案,请查看:https://github.com/u2ros/python-qt-multithreading – U2ros 2017-11-11 10:26:46
我知道它很久以前,但我只是偶然发现了同样的问题。
我一直在寻找一个合适的方法来做到这一点。最后这很容易。退出应用程序时,需要停止该任务,并且需要停止调用其退出方法的线程。请参阅底部的stop_thread方法。你需要等待线程完成。否则,您将获得QThread:线程仍在运行时销毁'消息,出口。
(我也改变了我的代码使用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_())
[http://qt-project.org/doc/qt-4.8/qthread.html#quit]真的应该是一路去这里......再试一次,也许在函数调用的时候进行一些基本的调试? – tmpearce 2013-04-27 00:22:31