Reputation: 3
I have a heavy task that constantly runs every 500ms. It consists of updating GUI elements and I need access to its variables at all times.
The task performed: A list that is dynamically updated and every 500ms, a loop goes through that list and performers tasks on the elements contained inside of it. Sometimes I have no elements in it, and sometimes I have plenty.
When the list is loaded, the user starts to encounter a delay in mouse movement, key presses, and such. And that's without a doubt due to the heavy task performed every 500ms.
Would there be a way for me to put this QTimer task into a QThread and constantly have access to it's elements in order update the list contained inside of it?
In other words, I would like it to run in the background at all times but also have the ability to update the list used inside of it at any given moment.
I'm using PySide2; I've seen examples but none that fit what I'm trying to accomplish.
EXAMPLE: I would like to update the "aList" element from the main thread as I wish. If the list is empty, then the for loop does not do anything. Otherwise, it loops over the elements and adds 1 to them.
The "run" function should have a Qtimer of 500ms set on it.
Sometimes the list may be empty and at times full of elements. It's size is controlled from the GUI thread.
from PySide2 import QtCore
from PySide2 import QtGui
from PySide2 import QtWidgets
import sys
import time
class RxProcess(QtCore.QThread):
output = QtCore.Signal()
def __init__(self, parent = None):
super(RxProcess, self).__init__(parent)
self.aList = list()
def run(self):
# Loop through list
for element in self.aList:
element += 1
# Print to the gui the element that was just updated in the list
self.output.emit(element)
Upvotes: 0
Views: 242
Reputation: 243907
With QThread it is difficult to implement that logic (you would have to use QThread.msleep, mutex, etc). Instead a simple solution is to create a new thread every T seconds and that will be implemented using threading.Thread + QTimer (can also be implemented with QThreadPool + QRunnable + QTimer):
import random
import sys
import threading
import time
from PySide2 import QtCore, QtWidgets
import shiboken2
class Worker(QtCore.QObject):
output = QtCore.Signal(object)
def long_running_function(values, worker):
for element in values:
time.sleep(0.1)
if shiboken2.isValid(worker):
worker.output.emit(element)
class Widget(QtWidgets.QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.label = QtWidgets.QLabel(alignment=QtCore.Qt.AlignCenter)
self.button = QtWidgets.QPushButton("Start")
lay = QtWidgets.QVBoxLayout(self)
lay.addWidget(self.button)
lay.addWidget(self.label)
self.timer = QtCore.QTimer(interval=500)
self.button.clicked.connect(self.handle_clicked)
self.timer.timeout.connect(self.launch_task)
def handle_clicked(self):
if self.button.text() == "Start":
self.timer.start()
self.button.setText("Stop")
elif self.button.text() == "Stop":
self.timer.stop()
self.button.setText("Start")
def launch_task(self):
values = random.sample(range(1, 50), 20)
worker = Worker()
worker.output.connect(self.label.setNum)
threading.Thread(
target=long_running_function,
args=(values, worker),
daemon=True,
).start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
w = Widget()
w.show()
sys.exit(app.exec_())
Upvotes: 1