2013-04-26 21 views
8

これは私が前に投稿した前の質問に対するフォローアップの質問です。 問題は、Qthreadをサブクラス化せず、むしろQObjectを作成し、それをQThreadに移動するという推奨される方法を使用するときに、GUIからQThreadを停止(終了|終了|終了)する方法です。下の例の場合。私はGUIとQthreadを起動することができ、後者はGUIを更新することができます。しかし、私はそれを止めることはできません。 qthread(quit()、exit()、terminate())のためにいくつかの方法を試してみました。 大変助かりました。ここでQThreadをGUIから停止する方法

は完全なコードです:

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

答えて

3

私は私の元の質問は1で、実際に二つの質問だったことが判明:メイン1からの二次スレッドを停止するためには、次の2つのものが必要:

  1. はトンを送る二次スレッドにダウンメインスレッドから

  2. を通信することができスレッド

を停止する彼の適切な信号Iは、(2)を解決することができていないが、私は私の元の問題に私の回避策を与えた、(1)を解決する方法を考え出しました。代わりにスレッドを停止するので、私はこの問題は、それが自身のイベントループを実行した場合、二次スレッドは信号のみに対応できるということですスレッドの処理longRunning()法)

を停止することができます。通常のQthread(私のコードで使われているもの)はそうではありません。

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

と私のコードの代わりに、元self.simulThread = Qthread()self.simulThread = MyThread()を使用:それは、その旨をQThreadのサブクラスを作成するために、しかし、十分に簡単です。 これは、セカンダリスレッドがイベントループを実行することを保証します。それだけでは十分ではありませんでした。 longRunning()メソッドは、メインスレッドからのイベントを実際に処理する機会が必要です。 this SO answerの助けを借りて、私はlongRunning()メソッドのQApplication.processEvent()の単純な追加が2次スレッドにこのような機会を与えたことを理解しました。スレッド自体を停止する方法がわからなくても、処理をでセカンダリスレッドで実行するのをやめることができます。

まとめてください。私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のサブクラスに加えて)仕事をこれらの3行があります。コメントは歓迎されている

self.simulThread = MyThread() 
    self.simulRunner.moveToThread(self.simulThread) 
    self.stopButton.clicked.connect(self.simulRunner.stop) 

を!

+0

私はこれに関して多くの問題を抱えていましたが、私自身の解決策を作りました。それをチェックしてください:https://github.com/u2ros/python-qt-multithreading – U2ros

6

私はその長いことを知っていますが、私はちょうど同じ問題を偶然見つけました。

私はこれを行う適切な方法を探しています。最後は簡単でした。アプリケーションを終了するときには、タスクを停止する必要があり、スレッドを停止してquitメソッドを呼び出す必要があります。下部の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_()) 
関連する問題