私は、自分のコントロール下にないスレッドから呼び出されたコールバックを介して外部ソースから情報を受け取り、QThread
ではないPyQtアプリケーションを持っています。このような情報をポーリングせずにメインスレッドに渡す正しい方法は何ですか?特に、新しいデータの到着時にメインスレッド(または別のQThread
)を起動できるように、Qtシグナルを出したいと思います。PyQtは非QThreadのメインスレッドをウェイクします
答えて
信号のデフォルトの接続タイプは、ドキュメントは、このように記述Qt.AutoConnectionある:
の信号を受信 オブジェクトとは異なるスレッドから出射された場合、信号は次のように動作し、キューイングされQt :: QueuedConnection。 それ以外の場合は、スロットが直接呼び出され、 Qt :: DirectConnectionとして動作します。接続のタイプは、 信号が放出されたときに決定されます。
ので、信号を発する前に、Qtは、単にそれをキューイングするかどうかを決定する前に、送信者と受信者の現在スレッドの親和性を比較します。重要ではない元のスレッドが最初に開始された方法。ここで
はPythonのワーカースレッドを使用して、簡単なデモです:import sys, time, threading
from PyQt4 import QtCore, QtGui
class Worker(object):
def __init__(self, callback):
self._callback = callback
self._thread = None
def active(self):
return self._thread is not None and self._thread.is_alive()
def start(self):
self._thread = threading.Thread(target=self.work, name='Worker')
self._thread.start()
def work(self):
print('work: [%s]' % threading.current_thread().name)
for x in range(5):
time.sleep(1)
self._callback(str(x))
class Window(QtGui.QPushButton):
dataReceived = QtCore.pyqtSignal(str)
def __init__(self):
super(Window, self).__init__('Start')
self.clicked.connect(self.start)
self.dataReceived.connect(self.receive)
self.worker = Worker(self.callback)
def receive(self, data):
print('received: %s [%s]' % (data, threading.current_thread().name))
def callback(self, data):
print('callback: %s [%s]' % (data, threading.current_thread().name))
self.dataReceived.emit(data)
def start(self):
if self.worker.active():
print('still active...')
else:
print('start: [%s]' % threading.current_thread().name)
self.worker.start()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
window = Window()
window.show()
print('show: [%s]' % threading.current_thread().name)
sys.exit(app.exec_())
典型的な出力:
$ python test.py
show: [MainThread]
start: [MainThread]
work: [Worker]
callback: 0 [Worker]
received: 0 [MainThread]
still active...
callback: 1 [Worker]
received: 1 [MainThread]
still active...
callback: 2 [Worker]
received: 2 [MainThread]
still active...
callback: 3 [Worker]
received: 3 [MainThread]
callback: 4 [Worker]
received: 4 [MainThread]
よあなたはQtを "送信者と受信者の現在のスレッドアフィニティと比較しました"と言っています:送信者のスレッドアフィニティはどのように定義されていますか?それは実際のスレッド(例えば 'threading.current_thread()')か、 'QObject'を送信するスレッド(あなたの例では' Worker'が作成されたときに間違ったスレッドになります)ですか?前者は、Qtのドキュメントの「スレッドアフィニティ」の定義に従っているのに対して、後者は「スレッドアフィニティ」の定義に準拠していますが、あなたの解決策を正しいものにすることができます。http://doc.qt.io/qt-5/qobject.html#thread-affinity – burnpanck
私の間違いは、あなたの例の送信オブジェクトは実際に受信オブジェクトと同じです、それは 'Window'です(信号' dataReceived'とスロット 'callback'は' Window'の一部です)。したがって、実際にドキュメントごとに「スレッドアフィニティ」を使用すると、間違ってダイレクトコールが実行されます。したがって、Qtは実際に実行中のスレッド(送信側のスレッドアフィニティではなく)を受信側のスレッドアフィニティと比較することになります。 @ burnpanck。 – burnpanck
はい、「送信者」は、実際にコールバック関数を呼び出すためのものです(これは参照先です)。 – ekhumoro
外部デバイスやライブラリをポーリングするのと同じ方法で処理します。コールバックを処理する別のワーカースレッドを作成し、メインのGUIスレッドに信号を送信します。
class Worker(QObject):
data_ready = pyqtSignal(object, object)
def callback(self, *args, **kwargs):
self.data_ready.emit(args, kwargs)
class Window(...)
def __init__(self):
...
self.worker = Worker(self)
# Connect worker callback function to your external library
library.register_callback(self.worker.callback) #??
...
# Mover worker to thread and connect signal
self.thread = QThread(self)
self.worker.data_ready.connect(self.handle_data)
self.worker.moveToThread(self.thread)
self.thread.start()
@pyqtSlot(object, object)
def handle_data(self, args, kwargs):
# do something with data
スレッド 'self.thread'は本当に必要なのでしょうか?それは何をしますか?' Worker.callback'関数はもちろん 'ライブラリによって作成された未知のエイリアンスレッド上で実行されます'... – burnpanck
- 1. PyQt QThreadによりメインスレッドが終了する
- 2. PyQt - QThreadからQMessageBoxを閉じる
- 3. QThreadをPyQtで使用する正しい方法の例?
- 4. QThread内のQTextEditのスタイルシートをpyqtで更新する
- 5. メインスレッドが他のすべてのQthreadが完了するまで待ちます。
- 6. Qthread PyQt 5から直接GUIを変更する
- 7. PyqtはQThreadを使用していますがGUIはまだ応答していません
- 8. Qthreadを使ってMatplotlibの図をPyQtで更新する方法は?
- 9. QThreadでQTcpServerを作成し、メインスレッドからQTcpServerを作成する方法
- 10. Qthreadはpython pyqtでguiを閉じるときにはまだ動作しています
- 11. スレッドセーフキューと疑似ウェイク
- 12. 非同期/待機のメインスレッドをブロックします
- 13. QThreadを正しく終了します
- 14. 非同期メソッドは、現在のスレッド(メインスレッド)でAsyncCallbackを開始します
- 15. QThreadはスレッドセーフです
- 16. Qt-新しいQThread(this)と新しいQThread()の違いは何ですか?
- 17. 実行中のQThreadから起動したPyQt Guiにどのように信号を送るのですか?
- 18. glfwInit()非メインスレッドからLWJGL 3状態の
- 19. Qthread - イベントまでスリープ
- 20. std :: threadはメインスレッドを検出します
- 21. NSFileManager removeItemAtPathはメインスレッドをロックします
- 22. xamlアニメーションはメインスレッドをブロックしますか?
- 23. IKImageBrowserView "--ImageKit Error:reloadDataが非メインスレッドで呼び出されました"
- 24. Pyqt GUIメインアプリケーションを別の非ブロッキングプロセスとして実行する
- 25. QThreadのmoveToThreadが機能しません
- 26. ウェイク状態の1文字入力
- 27. 非メインスレッドで非同期ioとdo ioの違いは何ですか?
- 28. メインスレッドのXMLHttpRequestは、My Ajaxリクエストで非推奨です
- 29. MVC - メインスレッドの同期XMLHttpRequestは非推奨です
- 30. QThreadスレッドプール
理解しないようにしてください、あなたは非qtのスレッドのソースコードを変更することはできません?完了したら信号を出すのが好きですか? – PyNico
私の制御下にあるのは、通常のPython関数であるコールバック関数だけです。私。信号を発信することはできますが、これは許可されますか?その関数を実行するスレッドは私のコードでは作成されず、Qtの概念も全くありません。だから、放射シグナルがスレッドセーフである(たとえQt以外のスレッドからでも)かどうか尋ねるべきでしょうか? – burnpanck
これはベストプラクティスか悪いのか分かりませんが、それは私のやり方です。あなたのコールバックからシグナルを送ります。私はそれがうまくいくと思う。 (Qtスレッドの安全性は接続の種類によって異なります:http://doc.qt.io/qt-4.8/threads-qobject.html#signals-and-slots-across-threads – PyNico