How to use a QTimer in a separate QThread

天涯浪子 提交于 2019-12-20 05:21:21

问题


I have some computationally heavy task that I want to run in a loop after every 5 seconds without blocking the main event-loop. For this, I intend to use a QTimer and a separate thread to run it. I have tried the following code but it has not worked so far:

@pyqtSlot()
def heavy_task_function():
    # Sleep for 10 seconds to simulate heavy computation
    time.sleep(10)
    print "First Timer Fired"

if __name__ == "__main__":
    app = QCoreApplication.instance()
    if app is None:
        app = QApplication(sys.argv)

    threaded_timer = ModbusComThread(heavy_task_function)
    threaded_timer.start()

    sys.exit(app.exec_())

Where:

class ModbusComThread(QThread):

    def __init__(self, slot_function):
        QThread.__init__(self)
        self.slot_function = slot_function
        self.send_data_timer = None

    def run(self):
        print "Timer started on different thread"
        self.send_data_timer = QTimer(self)
        self.send_data_timer.timeout.connect(self.slot_function)
        self.send_data_timer.start(5000)

    def stop(self):
        self.send_data_timer.stop()

The slot_function is never fired by the QTimer in threaded_timer. Is my threading architecture correct?


回答1:


A QTimer needs a running event-loop. By default, QThread.run() will start a local event-loop for the thread, but if you completely override it in the way that you have done, that won't happen - so the timer events will never be processed.

In general, when you need a local event-loop you should create a worker object to do all the processing and then use moveToThread to put it in a separate thread. If not, it's perfectly okay to override QThread.run().

The demo below shows how to do this. Note that it's very important to create the timer after the thread has started, otherwise it would be created in the wrong thread and its timer-events wouldn't be processed by the thread's event-loop. It's also important that all communication between the worker thread and the main thread is done via signals, so as to ensure thread-safety. Never try to directly perform GUI operations outside the main thread, as Qt does not support that at all. For the purposes of the demo, a second timer in the main thread is used to stop all processing after a fixed interval. If there was a GUI, user intervention via a button would achieve the same thing.

Demo:

import sys
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

class ModbusComWorker(QObject):
    finished = pyqtSignal()

    def start(self):
        self._timer = QTimer(self)
        self._timer.timeout.connect(self.process)
        self._timer.start(2000)

    def stop(self):
        self._timer.stop()
        self.finished.emit()

    def process(self):
        print('processing (thread: %r)' % QThread.currentThread())
        QThread.sleep(3)

if __name__ == "__main__":

    app = QCoreApplication.instance()
    if app is None:
        app = QApplication(sys.argv)

    thread = QThread()
    worker = ModbusComWorker()
    worker.moveToThread(thread)

    def finish():
        print('shutting down...')
        thread.quit()
        thread.wait()
        app.quit()
        print('stopped')

    worker.finished.connect(finish)
    thread.started.connect(worker.start)
    thread.start()

    timer = QTimer()
    timer.setSingleShot(True)
    timer.timeout.connect(worker.stop)
    timer.start(15000)

    print('starting (thread: %r)' % QThread.currentThread())

    sys.exit(app.exec_())

Output:

starting (thread: <PyQt5.QtCore.QThread object at 0x7f980d096b98>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
processing (thread: <PyQt5.QtCore.QThread object at 0x7f980d0968a0>)
shutting down...
stopped


来源:https://stackoverflow.com/questions/55651718/how-to-use-a-qtimer-in-a-separate-qthread

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