如何从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_()) 
+0

[http://qt-project.org/doc/qt-4.8/qthread.html#quit]真的应该是一路去这里......再试一次,也许在函数调用的时候进行一些基本的调试? – tmpearce 2013-04-27 00:22:31

我发现我原来的问题实际上是两个问题中的一个:为了从主要的一个停止辅助线程,你需要两样东西:

  1. 能够从主线程传达给辅助线程

  2. 发送ŧ他适当的信号停止线程

我一直没能解决(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) 

评论,欢迎!

+0

我遇到了很多问题,然后创建了我自己的解决方案,请查看: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_())