Python 如何从GUI停止QThread

Python 如何从GUI停止QThread,python,pyqt,pyqt4,qthread,Python,Pyqt,Pyqt4,Qthread,这是我先前发布的一个问题的后续问题。 问题在于,当使用建议的方法(不是子类化QThread,而是创建QObject,然后将其移动到QThread)时,如何从GUI停止(终止|退出|退出)QThread。下面是一个工作示例。我可以启动GUI和Qthread,然后让后者更新GUI。然而,我无法阻止它。我为qthread尝试了几种方法(quit()、exit(),甚至terminate()),但都没有成功。 非常感谢你的帮助 以下是完整的代码: import time, sys from PyQt4.

这是我先前发布的一个问题的后续问题。 问题在于,当使用建议的方法(不是子类化QThread,而是创建QObject,然后将其移动到QThread)时,如何从GUI停止(终止|退出|退出)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_())
导入时间,系统 从PyQt4.QtCore导入* 从PyQt4.QtGui导入* 类SimulRunner(QObject): “管理模拟的对象” stepIncreased=pyqtSignal(int,name='stepIncreased') 定义初始化(自): 超级(SimulRunner,self)。\uuuu init\uuuuu() 自。_步=0 self.\u isRunning=True 自。_最大步数=20 def长时间运行(自): 当self.\u step我发现我原来的问题实际上是两个问题合一:为了阻止主线程的次线程,需要两件事:

  • 能够从主线程到次线程进行通信

  • 发送正确的信号以停止螺纹

  • 我还没能解决(2),但我找到了解决(1)的方法,这给了我一个解决原来问题的方法。我可以停止线程的处理,而不是停止线程(使用
    longlunning()
    方法)

    问题是,次线程只有在运行自己的事件循环时才能响应信号。常规的Qthread(我的代码使用的是)没有。不过,将QThread子类化以实现这一效果非常容易:

    class MyThread(QThread):
        def run(self):
            self.exec_()
    
    并在我的代码中使用了
    self.simulThread=MyThread()
    ,而不是原来的
    self.simulThread=Qthread()
    。 这可确保次线程运行事件循环。但这还不够。
    longRunning()
    方法需要有机会实际处理从主线程发出的事件。在的帮助下,我发现在
    longlunning()
    方法中简单地添加
    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() 
    

    欢迎评论

    我知道这是很久以前的事了,但我只是被同样的问题绊倒了

    我也一直在寻找一个合适的方法来做到这一点。最后很容易。退出应用程序时,任务需要停止,线程需要停止调用其quit方法。请参阅底部的停止线程方法。您需要等待线程完成。否则,您将在线程仍在运行时在退出时收到“QThread:destromed”消息

    (我还将代码更改为使用pyside)

    导入时间,系统 从PySide.QtCore导入* 从PySide.QtGui导入* 班级工作人员(QObject): “管理模拟的对象” 步长增加=信号(int) 定义初始化(自): 超级(工作者,自我)。\uuuu初始化 自。_步=0 self.\u isRunning=True 自。_最大步数=20 def任务(自我): 如果不是自运行,请执行以下操作: self.\u isRunning=True 自。_步=0 当self.\u step self.simulThread = MyThread() self.simulRunner.moveToThread(self.simulThread) self.stopButton.clicked.connect(self.simulRunner.stop)
    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_())