Reputation: 153
I have created the following toy class with help from 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_()
How can I start the timer from a new thread when I use QThreadPool
?
I need to update the GUI repeatedly at regular intervals but if I add the QTimer
in the main thread the whole application feels really sluggish. My understanding is that by including this in a separate thread through QThreadPool
it may be a more efficient solution as the new thread can be self deleted automatically once it is done.
However, whenever I change QtCore.QThread
to QtCore.QRunnable
in the above class and I try to start the thread using the code below I get an error:
self.threadpool = QtCore.QThreadPool()
worker = Worker()
self.threadpool.start(worker)
Upvotes: 1
Views: 1287
Reputation: 243955
If you want to run a task every T seconds with a QThreadPool then it is not necessary for the QTimer to live in another thread, but for the QTimer to start the 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_())
Upvotes: 4