2013-04-26 90 views
8

這是對之前發佈的前一個問題的跟進問題。 問題是如何在使用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

回答

3

我發現我原來的問題實際上是兩個問題中的一個:爲了從主要的一個停止輔助線程,你需要兩樣東西:

  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

6

我知道它很久以前,但我只是偶然發現了同樣的問題。

我一直在尋找一個合適的方法來做到這一點。最後這很容易。退出應用程序時,需要停止該任務,並且需要停止調用其退出方法的線程。請參閱底部的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_())