Таймер в QRunnable - PullRequest
       62

Таймер в QRunnable

0 голосов
/ 26 мая 2020

Я создал следующий класс игрушек с помощью этого ответа :

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 в основной поток, все приложение почувствует себя действительно вялым sh. Насколько я понимаю, включение этого в отдельный поток через QThreadPool может быть более эффективным решением, поскольку новый поток может быть автоматически удален автоматически, как только это будет сделано.

Однако всякий раз, когда я меняю QtCore.QThread на QtCore.QRunnable в указанном выше классе, и я пытаюсь запустить поток, используя приведенный ниже код, и получаю сообщение об ошибке:

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

1 Ответ

2 голосов
/ 26 мая 2020

Если вы хотите запускать задачу каждые T секунд с QThreadPool, тогда 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_())
...