40

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

https://mayaposch.wordpress.com/2011/11/01/how-to-really-truly-use-qthreads-the-full-explanation/を読みました。そのページは、メソッドを再実装するrunことはそれを行う方法ではないと述べています。私が抱えている問題は、Gui を実行するメイン スレッドとそれを実行しないワーカー スレッドを持つ PyQt の例を見つけることです。ブログの投稿は C++ 向けなので、例は役に立ちますが、まだ少し迷っています。誰かがPythonでそれを行う正しい方法の例を教えてもらえますか?

4

3 に答える 3

0

メインスレッドがGUIを実行している間にワーカースレッドが処理を実行するのは良いことです。また、PyQt は、スレッド セーフなシグナル/スロット メカニズムを備えたスレッド インストルメンテーションを提供しています。

これは興味深いかもしれません。彼らの例では、彼らは 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)

(ボタンをクリックしてアイテムを追加するリスト ウィジェットを含むシンプルな UI)

その後、独自のスレッド クラスを作成できます。1 つの例は次のとおりです。

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()。チュートリアルを参照してください。

于 2013-06-02T06:21:17.423 に答える
0

私の意見では、最初は応答せず、その後改善されるコード例を使用した、はるかに最良の説明は、ここにあります。

これは実際に望ましい(サブクラス化されていない)アプローチQThreadを使用していることに注意してください。これはmoveToThread、記事が推奨されるアプローチであると主張しています。

上記のリンクされたページは、2011 年からMaya Posch による決定的な説明を提供する C Qt ページに相当する PyQt5 も提供します。彼女はおそらく当時 Qt4 を使用していたと思いますが、そのページは Qt5 (したがって PyQt5) にまだ適用可能であり、十分に価値があります。多くのコメント (および彼女の返信) を含め、深く研究しています。

上記の最初のリンクが 404 になった場合に備えて (これはひどいことです!)、これは Maya の C コードに相当する重要な Python コードです。

self.thread = QtCore.QThread()
# Step 3: Create a worker object
self.worker = Worker()
# Step 4: Move worker to the thread
self.worker.moveToThread(self.thread)
# Step 5: Connect signals and slots
self.thread.started.connect(self.worker.run)
self.worker.finished.connect(self.thread.quit)
self.worker.finished.connect(self.worker.deleteLater)
self.thread.finished.connect(self.thread.deleteLater)
self.worker.progress.connect(self.reportProgress)
# Step 6: Start the thread
self.thread.start()

# Final resets
self.longRunningBtn.setEnabled(False)
self.thread.finished.connect(
    lambda: self.longRunningBtn.setEnabled(True)
)
self.thread.finished.connect(
    lambda: self.stepLabel.setText("Long-Running Step: 0")
)   

selfそのページの例のNBがQMainWindowオブジェクトです。インスタンスをプロパティとして何にアタッチするかについては、非常に注意する必要があると思いますQThread: スコープ外に出ると破棄されるが、QThreadプロパティを持つインスタンス、または実際にはスコープ外になるローカルQThreadインスタンスは、機能しているように見えます。sys.excepthook(または)によって検出されない、いくつかの不可解な Python クラッシュの原因となりsys.unraisablehookます。注意が必要です。

...Worker次のようになります。

class Worker(QtCore.QObject):
    finished = QtCore.pyqtSignal()
    progress = QtCore.pyqtSignal(int)

    def run(self):
        """Long-running task."""
        for i in range(5):
            sleep(1)
            self.progress.emit(i + 1)
        self.finished.emit()
于 2021-08-14T09:54:17.903 に答える