How to use QTimer inside QThread which uses QWaitCondition? (pyside)

好久不见. 提交于 2020-01-01 19:27:13

问题


I'm using pyside but (I think) is a generic Qt question.

I know that QThread implementation calls ._exec() method so we should have an event loop on a started QThread. This way we can use QTimer on that thread (I've done this and it works perfectly). My problem is when QWaitCondition is also used, I'd like to have a "consumer" thread with a infinite loop waiting to be notify (from producers) on the QWaitCondition. The problem I have is that with this design I cannot use QTimer inside the consumer Thread.

This is a snippet of the scenario I'm trying to explain:

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_())

Once you click the button we obtain an output like this:

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

This means that the QTimer created inside loop() method is never executed by the event loop.

If I change the design from QWaitCondition to Signals (which is better design imho) the QTimer works, but I'd like to know why they are not working when QWaitCondition is used.


回答1:


To still process events in a long running task (aka a continuous loop) you need to call QCoreApplication::processEvents().

This will essentially go through all of the queued up slots for your thread.

Calling this function is also necessary for signals (if they are a QueuedConnection signal/slot connection) to make it out of the current thread and into another one.


For PySides, you will need to call PySide.QtCore.QCoreApplication.processEvents()




回答2:


Your method loop completely occupies thread. It doesn't return control to event loop. Timer sends its events to event loop which doesn't gain control.
IMO your wile loop is faulty.

One way to fix it is add QApplication.processEvents() in loop (bad approach).

I think you want something else, here are my corrections:

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()

this will invoke do_stuff_timer every second until you will call stop.



来源:https://stackoverflow.com/questions/15025644/how-to-use-qtimer-inside-qthread-which-uses-qwaitcondition-pyside

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!