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 你的诡计循环有问题。

解决它的一种方法是添加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一次,直到您调用停止。

于 2013-02-22T14:05:51.367 回答