Корректно ли отправлять класс наследуемый от QThread в свой поток?
Я наследую класс Worker от PyQt5.QtCore.QThread. В нём я определяю функцию, которую хочу исполнить в отдельном потоке, а конкретно именно в том же экземпляре Worker, что и сама функция. Что бы исполнить, нужно перенести на нужный поток QObject с помощью moveToThread. Так как функция в классе, наследуемом от QThread, то я получается переношу поток сам в себя.
from PyQt5.QtCore import QThread
class Worker(QThread):
def __init__(self, func, signals):
super().__init__()
self.func = func
self.signals = signals
self.moveToThread(self)
self.args = []
self.kwargs = {}
def execute_function(self):
self.func(*self.args, **self.kwargs)
self.signals.finished.emit()
def __call__(self, *args, **kwargs):
self.args = args
self.kwargs = kwargs
self.start()
С ошибкой это не падает, функция выполняется в отдельном потоке. Но как-то очень сомнительно делать self.moveToThread(self). Можно ли так делать?
Ответы (1 шт):
Автор решения: S. Nick
→ Ссылка
Реализация QThread-moveToThread выглядит так:
from PyQt5 import QtCore, QtWidgets
class Worker(QtCore.QObject):
started = QtCore.pyqtSignal()
finished = QtCore.pyqtSignal()
data = QtCore.pyqtSignal(str)
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.running = False
@QtCore.pyqtSlot()
def read_data_from_sensor(self):
self.started.emit()
QtCore.QThread.msleep(1000) # Моделируем процесс блокировки
while self.running:
dt = QtCore.QDateTime.currentDateTime().toString('hh:mm:ss')
self.data.emit(dt)
QtCore.QThread.msleep(1000) # Моделируем процесс блокировки
self.finished.emit()
class App(QtWidgets.QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("Реализация QThread-moveToThread")
self.resize(400, 300)
centralWidget = QtWidgets.QWidget(self)
self.setCentralWidget(centralWidget)
self.boton = QtWidgets.QPushButton('Начать', self)
self.boton.clicked.connect(self.read_data)
self.label_data = QtWidgets.QLabel(self, alignment=QtCore.Qt.AlignCenter)
self.label_data.setText('В ожидании')
self.label_data.adjustSize()
layout = QtWidgets.QGridLayout(centralWidget)
layout.addWidget(self.label_data)
layout.addWidget(self.boton)
self._worker = Worker() # Worker
self._worker.started.connect(self.on_started)
self._worker.finished.connect(self.on_finished)
self._worker.data.connect(self.update_label)
self._thread = QtCore.QThread(self) # QThread
self._thread.start()
self._worker.moveToThread(self._thread)
@QtCore.pyqtSlot()
def on_started(self):
""" slot будет вызван, когда начнется сбор данных """
self.label_data.setText("Начиная читать")
self.boton.setText("Стоп")
self.boton.setEnabled(True)
@QtCore.pyqtSlot()
def on_finished(self):
""" slot будет вызван, когда сбор данных закончится """
self.label_data.setText("В ожидании")
self.boton.setText("Начать")
self.boton.setEnabled(True)
@QtCore.pyqtSlot()
def read_data(self):
""" Начать / остановить чтение при нажатии кнопки """
if self._worker.running:
self._worker.running = False
else:
self._worker.running = True
QtCore.QTimer.singleShot(0, self._worker.read_data_from_sensor)
self.boton.setEnabled(False)
@QtCore.pyqtSlot(str)
def update_label(self, data):
""" Slot будет вызываться при появлении новых данных в метке """
self.label_data.setText(data)
if __name__ == "__main__":
import sys
app = QtWidgets.QApplication(sys.argv)
ventana = App()
ventana.show()
sys.exit(app.exec_())
