2

私はpysideを使用していますが、(私は)一般的なQtの質問です。

QThreadの実装が._exec()メソッドを呼び出すことを知っているので、開始されたQThreadでイベントループが必要です。このようにして、そのスレッドでQTimerを使用できます(これを実行しましたが、完全に機能します)。私の問題は、QWaitConditionも使用されている場合、QWaitConditionで(プロデューサーからの)通知を待機する無限ループの「コンシューマー」スレッドが欲しいということです。私が抱えている問題は、このデザインではコンシューマースレッド内でQTimerを使用できないことです。

これは私が説明しようとしているシナリオの抜粋です:

from PySide import QtGui
from PySide import QtCore
import sys

class MainWindow(QtGui.QMainWindow):
    def __init__(self):
        super(MainWindow, self).__init__()

        self.button = QtGui.QPushButton(self)
        self.button.setText("Periodical")
        self.button.clicked.connect(self.periodical_call)

        self.thread = QtCore.QThread()
        self.worker = Worker()
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.loop)
        self.thread.start()

    def closeEvent(self, x):
        self.worker.stop()
        self.thread.quit()
        self.thread.wait()

    def periodical_call(self):
        self.worker.do_stuff("main window") # this works
        self.timer = QtCore.QTimer()
        self.timer.timeout.connect(self.do_stuff) # this also works
        self.timer.start(2000)

    def do_stuff(self):
        self.worker.do_stuff("timer main window")

class Worker(QtCore.QObject):
    def do_stuff_timer(self):
        do_stuff("timer worker")

    def do_stuff(self, origin):
        self.origin = origin
        self.wait.wakeOne()

    def stop(self):
        self._exit = True
        self.wait.wakeAll()

    def loop(self):
        self.wait = QtCore.QWaitCondition()
        self.mutex = QtCore.QMutex()
        self._exit = False
        while not self._exit:
            self.wait.wait(self.mutex)

            print "loop from %s" % (self.origin,)

            self.timer = QtCore.QTimer()
            self.timer.setSingleShot(True)
            self.timer.timeout.connect(self.do_stuff_timer)
            self.timer.start(1000) # <---- this doesn't work

if __name__ == '__main__':
    app = QtGui.QApplication(sys.argv)
    frame = MainWindow()
    frame.show()
    sys.exit(app.exec_())

ボタンをクリックすると、次のような出力が得られます。

loop from main window                    
loop from timer main window
loop from timer main window
loop from timer main window
...

これは、loop()メソッド内で作成されたQTimerがイベントループによって実行されないことを意味します。

デザインをQWaitConditionからSignalsに変更すると(これはより良いデザインです)、QTimerは機能しますが、QWaitConditionを使用したときになぜ機能しないのか知りたいです。

4

2 に答える 2

6

長時間実行されるタスク(別名、連続ループ)でイベントを処理するには、を呼び出す必要がありますQCoreApplication::processEvents()

これは基本的に、スレッドのキューに入れられたすべてのスロットを通過します。

この関数を呼び出すことは、シグナル(QueuedConnectionシグナル/スロット接続の場合)が現在のスレッドから別のスレッドにそれを作成するためにも必要です。


PySidesの場合は、電話する必要がありますPySide.QtCore.QCoreApplication.processEvents()

于 2013-02-22T13:58:16.080 に答える
3

あなたのメソッドloopは完全にスレッドを占有します。制御をイベントループに戻しません。タイマーは、制御を取得しないイベントループにイベントを送信します。
IMOのワイルループに障害があります。

これを修正する1つの方法は、ループ内に追加することですQApplication.processEvents()(悪いアプローチ)。

私はあなたが何か他のものが欲しいと思います、ここに私の訂正があります:

def loop(self):
    self.timer = QtCore.QTimer()
    self.timer.setSingleShot(False)
    self.timer.timeout.connect(self.do_stuff_timer)
    self.timer.start(1000)

def stop(self):
    self.timer.stop()

これはdo_stuff_timer、stopを呼び出すまで、毎秒呼び出されます。

于 2013-02-22T14:05:51.367 に答える