2013-06-02 32 views
23

私はPyTt GuiアプリケーションでQThreadsを使用する方法を学ぼうとしています。私はGuiを更新することができる(通常)ポイントで、しばらくの間実行されているものがありますが、私は自分のスレッドに主要な作業を分割したい(時々ものがつまって、それは最終的にメインループがブロックされているため、Guiがフリーズしても明らかに機能しません)。QThreadをPyQtで使用する正しい方法の例?

私はhttps://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/と書いてあります。そのページには、runメソッドを再実装する方法がありません。私が抱えている問題は、メインスレッドがGuiをやっているPyQtの例と、そうしないワーカスレッドを見つけることです。ブログの投稿はC++用ですので、例が助けになりますが、私はまだ少し失われています。誰かがPythonでそれを行う正しい方法の例を教えてください。

+4

これは[PyQtはでQThreadとバックグラウンドスレッド(http://stackoverflow.com/questions/6783194/background-thread-with-qthread-in-pyqt)のDUPのように見えます。受け入れられた答えの2番目の例は、リンクしたブログからC++コードを直接変換したものです。 – abarnert

+0

また、ネイティブのPythonスレッドコード( 'threading.Thread'など)を書いていますか?そうでない場合は、最初にその例をいくつか試してみてください。 (「PyQtアプリケーションでのスレッド化:QtスレッドまたはPythonスレッドの使用」も参照してください(http://stackoverflow.com/questions/1595649/threading-in-a-pyqt-application-use-qt-threads-or-python-あなたがQThreadを必要とするかどうかを知るため)。 – abarnert

+0

@abarnertありがとう、私はそのリンクが私が探していたものだと思う。私は2番目のリンクを見て、スレッド間でスロット/シグナルを送信できるようにするためにQThreadsを使うべきだと決めました。私は 'threading.Thread'が存在することを知っていましたが、以前はそれを使用していませんでした。私は多くの検索をして、最初のリンクを見て、それを飛ばして、「def run」を見て、移動して、両方の方法を示していないことを実現しなかった! – Azendale

答えて

7

ここでは、GUIと通信できるように信号を送受信できる別のワーカースレッドの実例を示します。

2つの単純なボタンを作成しました.1つは別のスレッドで長い計算を開始し、もう1つは計算を直ちに終了してワーカースレッドをリセットします。

ここで行われているように強制的にスレッドを終了させるのは一般的には最善の方法ではありませんが、常に優雅に終了するオプションはありません。

from PyQt4 import QtGui, QtCore 
import sys 
import random 

class Example(QtCore.QObject): 

    signalStatus = QtCore.pyqtSignal(str) 

    def __init__(self, parent=None): 
     super(self.__class__, self).__init__(parent) 

     # Create a gui object. 
     self.gui = Window() 

     # Setup the worker object and the worker_thread. 
     self.worker = WorkerObject() 
     self.worker_thread = QtCore.QThread() 
     self.worker.moveToThread(self.worker_thread) 
     self.worker_thread.start() 

     # Make any cross object connections. 
     self._connectSignals() 

     self.gui.show() 

    def _connectSignals(self): 
     self.gui.button_start.clicked.connect(self.worker.startWork) 
     self.gui.button_cancel.clicked.connect(self.forceWorkerReset) 
     self.signalStatus.connect(self.gui.updateStatus) 
     self.worker.signalStatus.connect(self.gui.updateStatus) 

     self.parent().aboutToQuit.connect(self.forceWorkerQuit) 

    def forceWorkerReset(self): 
     if self.worker_thread.isRunning(): 
      self.worker_thread.terminate() 
      self.worker_thread.wait() 

      self.signalStatus.emit('Idle.') 
      self.worker_thread.start() 

    def forceWorkerQuit(self): 
     if self.worker_thread.isRunning(): 
      self.worker_thread.terminate() 
      self.worker_thread.wait() 


class WorkerObject(QtCore.QObject): 

    signalStatus = QtCore.pyqtSignal(str) 

    def __init__(self, parent=None): 
     super(self.__class__, self).__init__(parent) 

    @QtCore.pyqtSlot()   
    def startWork(self): 
     for ii in range(7): 
      number = random.randint(0,5000**ii) 
      self.signalStatus.emit('Iteration: {}, Factoring: {}'.format(ii, number)) 
      factors = self.primeFactors(number) 
      print('Number: ', number, 'Factors: ', factors) 
     self.signalStatus.emit('Idle.') 

    def primeFactors(self, n): 
     i = 2 
     factors = [] 
     while i * i <= n: 
      if n % i: 
       i += 1 
      else: 
       n //= i 
       factors.append(i) 
     if n > 1: 
      factors.append(n) 
     return factors 


class Window(QtGui.QWidget): 

    def __init__(self): 
     QtGui.QWidget.__init__(self) 
     self.button_start = QtGui.QPushButton('Start', self) 
     self.button_cancel = QtGui.QPushButton('Cancel', self) 
     self.label_status = QtGui.QLabel('', self) 

     layout = QtGui.QVBoxLayout(self) 
     layout.addWidget(self.button_start) 
     layout.addWidget(self.button_cancel) 
     layout.addWidget(self.label_status) 

     self.setFixedSize(400, 200) 

    @QtCore.pyqtSlot(str) 
    def updateStatus(self, status): 
     self.label_status.setText(status) 


if __name__=='__main__': 
    app = QtGui.QApplication(sys.argv) 
    example = Example(app) 
    sys.exit(app.exec_()) 
+0

これを実行すると、私は取得します。 'Qtがイベントハンドラからスローされた例外を検出しました。イベントハンドラからの例外のスローはQtではサポートされていません。 QApplication :: notify()を再実装し、すべての例外をキャッチする必要があります。 ' –

+0

例外は何ですか?私はこのスニペットを、Python 2.7でOS X上でPyQt4を使用してエラーなくテストしました。これをPython 3.4で使用しようとすると、時々セグメンテーションフォルトが発生します。この問題が書かれたコードや特定の(バージョン固有の)実装であるかどうかはわかりません。 – amicitas

+0

私は何を投げているのか調査していませんが、まれにメッセージループに例外がスローされることがあります。 –

0

メインスレッドがGUIを実行している間にワーカースレッドが処理を実行することは良いことです。また、PyQtは、スレッドセーフであるシグナル/スロット機構をスレッド計測に提供しています。

This may sound of interest。その例では、彼らはあなたが、その後1 exempleがあり、私たち自身のスレッドクラスを作成することもGUI

import sys, time 
from PyQt4 import QtCore, QtGui 

class MyApp(QtGui.QWidget): 
def __init__(self, parent=None): 
    QtGui.QWidget.__init__(self, parent) 

    self.setGeometry(300, 300, 280, 600) 
    self.setWindowTitle('threads') 

    self.layout = QtGui.QVBoxLayout(self) 

    self.testButton = QtGui.QPushButton("test") 
    self.connect(self.testButton, QtCore.SIGNAL("released()"), self.test) 
    self.listwidget = QtGui.QListWidget(self) 

    self.layout.addWidget(self.testButton) 
    self.layout.addWidget(self.listwidget) 

def add(self, text): 
    """ Add item to list widget """ 
    print "Add: " + text 
    self.listwidget.addItem(text) 
    self.listwidget.sortItems() 

def addBatch(self,text="test",iters=6,delay=0.3): 
    """ Add several items to list widget """ 
    for i in range(iters): 
    time.sleep(delay) # artificial time delay 
    self.add(text+" "+str(i)) 

def test(self): 
    self.listwidget.clear() 
    # adding entries just from main application: locks ui 
    self.addBatch("_non_thread",iters=6,delay=0.3) 

(私たちはボタンをクリックしてにいくつかの項目を追加するリストウィジェットを含むsimpel UI)

を構築します

class WorkThread(QtCore.QThread): 
def __init__(self): 
    QtCore.QThread.__init__(self) 

def __del__(self): 
    self.wait() 

def run(self): 
    for i in range(6): 
    time.sleep(0.3) # artificial time delay 
    self.emit(QtCore.SIGNAL('update(QString)'), "from work thread " + str(i)) 

    self.terminate() 

run()メソッドを再定義します。 terminate()の代替案が見つかります。チュートリアルをご覧ください。

+9

OPは、特に彼が 'QThread.run'メカニズムではなく' moveToThread'メカニズムを使いたいと言っています。彼にはそれが良い理由があるのか​​どうかはわかりませんが、依然として彼の質問に答えていません。 – abarnert

+1

OPが正しいです:QThreadをサブクラス化しないでください。 http://blog.qtを参照してください。io/blog/2010/06/17/youre-doing-it-wrong/ – blokeley

+0

[スレッド上のQtドキュメント](http://doc.qt.io/qt-4.8/thread-basics.html#gui-thread - と - ワーカースレッド)は、QThreadのサブクラス化については言及しています... –

関連する問題