如何从GUI停止的QThread(How to stop a QThread from the GU

2019-09-01 06:20发布

这是前一个我刚才发布了跟进的问题。 问题是如何阻止(终止|出口|退出)使用的不是继承的QThread,而是vreating一个QObject,然后将它移动到的QThread推荐的方法时从GUI的QThread。 下面,如果一个工作示例。 我可以启动GUI和QThread的,我可以有后者更新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_())

Answer 1:

我以前知道它的长,但我只是绊了同样的问题。

我一直也寻找一个合适的方式来做到这一点。 最后,它很容易。 当退出应用程序的任务需要停止和线程需要停止调用它的退出方法。 查看底部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_())


Answer 2:

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

  1. 能够从主线程进行通信第二螺纹

  2. 发送正确的信号停止线程

我一直没能解决(2),但我想通了,如何解决(1),这给了我一个解决方法,我原来的问题。 相反,停止线的,我可以停止线程的处理longRunning()方法)

问题是,如果它运行其自己的事件循环AA辅助线程只能对信号做出响应。 定期的QThread(这是用我的代码)不。 这是很容易的,但是,子类的QThread该效果:

class MyThread(QThread):
    def run(self):
        self.exec_()

和使用self.simulThread = MyThread()在我的代码,而不是原始self.simulThread = Qthread() 这确保了辅助线程运行的事件循环。 这还不够,虽然。 该longRunning()方法需要有机会实际处理从主线程下来的事件。 的帮助下这个SO回答我想通了,简单的添加的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)

评论欢迎!



文章来源: How to stop a QThread from the GUI