【问题标题】:Timer in a QRunnableQRunnable 中的计时器
【发布时间】:2020-05-26 15:45:56
【问题描述】:

我在this answer 的帮助下创建了以下玩具类:

class Worker(QtCore.QThread):
    def work(self):
        print("message")

    def __init__(self):
        super(Worker, self).__init__()
        self.timer = QtCore.QTimer() 
        self.timer.moveToThread(self)
        self.timer.timeout.connect(self.work)

    def run(self):
        self.timer.start(1000)
        loop = QtCore.QEventLoop()
        loop.exec_()

当我使用QThreadPool 时,如何从新线程启动计时器?

我需要定期重复更新 GUI,但如果我在主线程中添加 QTimer,整个应用程序会感觉非常缓慢。我的理解是,通过 QThreadPool 将其包含在单独的线程中,这可能是一个更有效的解决方案,因为新线程可以在完成后自动自行删除。

但是,每当我在上面的类中将 QtCore.QThread 更改为 QtCore.QRunnable 并尝试使用下面的代码启动线程时,我都会收到错误:

self.threadpool = QtCore.QThreadPool()
worker = Worker()
self.threadpool.start(worker)

【问题讨论】:

    标签: python python-3.x pyqt5 pyside2


    【解决方案1】:

    如果您想使用 QThreadPool 每 T 秒运行一次任务,那么 QTimer 不必存在于另一个线程中,而是 QTimer 启动 QRunnable:

    import json
    import random
    import threading
    import time
    
    from PyQt5 import QtCore, QtGui, QtWidgets
    import sip
    
    
    class Signaller(QtCore.QObject):
        dataChanged = QtCore.pyqtSignal(object)
    
    
    class TimerRunnable(QtCore.QRunnable):
        def __init__(self):
            super().__init__()
            self._signaller = Signaller()
    
        @property
        def signaller(self):
            return self._signaller
    
        def run(self):
            print("secondary thread:", threading.current_thread())
            time.sleep(0.5)
            r = random.choice(("hello", (1, 2, 3), {"key": "value"}))
            print("send:", r)
            if not sip.isdeleted(self.signaller):
                self.signaller.dataChanged.emit(r)
    
    
    class Widget(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super().__init__(parent)
    
            self.text_edit = QtWidgets.QTextEdit()
            self.setCentralWidget(self.text_edit)
    
            timer = QtCore.QTimer(self, timeout=self.on_timeout, interval=1000)
            timer.start()
    
        @QtCore.pyqtSlot()
        def on_timeout(self):
            runnable = TimerRunnable()
            runnable.signaller.dataChanged.connect(self.on_data_changed)
            QtCore.QThreadPool.globalInstance().start(runnable)
    
        @QtCore.pyqtSlot(object)
        def on_data_changed(self, data):
            text = json.dumps(data)
            self.text_edit.append(text)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
    
        w = Widget()
        w.show()
    
        print("main thread:", threading.current_thread())
    
        sys.exit(app.exec_())
    

    【讨论】:

    • 我明白你的意思,但是如果我在主 GUI 线程中有多个计时器,这不会降低它的响应能力吗?
    • @Giuseppe QTimer 只有一个
    • 在本例中是。但是,如果我有其他计时器更新 GUI 的不同部分,这不会成为问题吗?
    • @Giuseppe QTimers 不会产生开销,您有多少个 QTImer?
    • @Giuseppe mmm,plop,4 个 QTimer 不会产生开销。每个 QTimer 都使用事件循环来查看是否到了触发信号的时间。一般来说,信号使用事件循环,它们不排队。
    猜你喜欢
    • 2017-02-21
    • 1970-01-01
    • 1970-01-01
    • 2013-05-23
    • 1970-01-01
    • 2012-11-26
    • 2013-12-28
    • 1970-01-01
    • 2013-12-17
    相关资源
    最近更新 更多