运行 作为 QThread 的繁重的 QTimer 任务
Running a heavy QTimer task as a QThread
我有一项繁重的任务,每 500 毫秒不断 运行s。它包括更新 GUI 元素,我需要随时访问它的变量。
执行的任务:一个动态更新的列表,每 500 毫秒,一个循环遍历该列表并对其中包含的元素执行任务。有时我没有元素,有时我有很多。
加载列表后,用户开始遇到鼠标移动、按键等方面的延迟。毫无疑问,这是因为每 500 毫秒执行一次繁重的任务。
我是否可以将此 QTimer 任务放入 QThread 并不断访问它的元素以更新其中包含的列表?
换句话说,我希望它始终 运行 在后台运行,但也能够随时更新其中使用的列表。
我正在使用 PySide2;我看过示例,但 none 符合我想要完成的目标。
示例:
我想根据需要从主线程更新“aList”元素。如果列表为空,则 for 循环不执行任何操作。否则,它循环遍历元素并将它们加 1。
“运行”函数应设置 500 毫秒的 Qtimer。
有时列表可能是空的,有时又充满了元素。它的大小由 GUI 线程控制。
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)
使用 QThread 很难实现该逻辑(您将不得不使用 QThread.msleep、互斥锁等)。相反,一个简单的解决方案是每 T 秒创建一个新线程,这将使用 threading.Thread + QTimer 实现(也可以使用 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_())
我有一项繁重的任务,每 500 毫秒不断 运行s。它包括更新 GUI 元素,我需要随时访问它的变量。
执行的任务:一个动态更新的列表,每 500 毫秒,一个循环遍历该列表并对其中包含的元素执行任务。有时我没有元素,有时我有很多。
加载列表后,用户开始遇到鼠标移动、按键等方面的延迟。毫无疑问,这是因为每 500 毫秒执行一次繁重的任务。
我是否可以将此 QTimer 任务放入 QThread 并不断访问它的元素以更新其中包含的列表?
换句话说,我希望它始终 运行 在后台运行,但也能够随时更新其中使用的列表。
我正在使用 PySide2;我看过示例,但 none 符合我想要完成的目标。
示例: 我想根据需要从主线程更新“aList”元素。如果列表为空,则 for 循环不执行任何操作。否则,它循环遍历元素并将它们加 1。
“运行”函数应设置 500 毫秒的 Qtimer。
有时列表可能是空的,有时又充满了元素。它的大小由 GUI 线程控制。
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)
使用 QThread 很难实现该逻辑(您将不得不使用 QThread.msleep、互斥锁等)。相反,一个简单的解决方案是每 T 秒创建一个新线程,这将使用 threading.Thread + QTimer 实现(也可以使用 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_())