Home > Enterprise >  Is there a way to return a dataclass from a QThread in PyQt5
Is there a way to return a dataclass from a QThread in PyQt5

Time:11-04

I am trying to update a dataclass in a QThread using PyQt5, but I cannot seem to work out how to return the updated class from the thread. I have tried finished = pyqtSignal(dataclass), finished = pyqtSignal(class), finished = pyqtSignal(<class>) etc but none of them seem to work.

Below is a cut down piece of code that should be reproducible.

import sys
from dataclasses import dataclass

from PyQt5.QtWidgets import *
from PyQt5.QtGui import *
from PyQt5.QtCore import *

@dataclass
class info():
    fname : str = "8888"
    lname : str = "8888"

class testThread(QObject):
    finished = pyqtSignal()

    def __init__(self, data):
        super().__init__()

        self.data = data
        print(data)

    def run(self):
        print("Update dataclass")

        self.data.fname = "Bob"
        self.data.lname = "Alob"

        self.finished.emit(self.data)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.data = info()

        self.setWindowTitle("My App")
        self.resize(200, 200)

        self.lblOne = QLabel("Old Text", self)
        self.lblOne.move(40, 20)
        self.lblOne.resize(100,100)

        self.lblTwo = QLabel("Old Text", self)
        self.lblTwo.move(40, 40)
        self.lblTwo.resize(100,100)

        self.btn = QPushButton("Update Labels", self)
        self.btn.move(40, 100)
        self.btn.clicked.connect(self.runThread)

    def runThread(self):
        self.thread = QThread()
        self.worker = testThread(self.data)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.thread.start()

        self.thread.finished.connect(lambda: self.evt_onFinished(data))

    def evt_onFinished(self):
        "Update the labels with the information from the returned/updated dataclass"""

if __name__ == "__main__":
    app = QApplication(sys.argv)
    mnuMain = MainWindow()
    mnuMain.show()
    sys.exit(app.exec_())

Is it even possible to return a dataclass from a QThread in PyQt5?

CodePudding user response:

Dataclasses are like any class so you must use the name of the class. On the other hand you are connecting the finished signal of the QThread instead of the worker.

import sys
from dataclasses import dataclass


from PyQt5.QtCore import pyqtSignal, QObject, QThread
from PyQt5.QtWidgets import QApplication, QLabel, QMainWindow, QPushButton


@dataclass
class Info:
    fname: str = "8888"
    lname: str = "8888"


class testThread(QObject):
    finished = pyqtSignal(Info)

    def __init__(self, data):
        super().__init__()

        self.data = data
        print(data)

    def run(self):
        print("Update dataclass")
        self.data.fname = "Bob"
        self.data.lname = "Alob"
        self.finished.emit(self.data)


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()

        self.setWindowTitle("My App")
        self.resize(200, 200)

        self.lblOne = QLabel("Old Text", self)
        self.lblOne.move(40, 20)
        self.lblOne.resize(100, 100)

        self.lblTwo = QLabel("Old Text", self)
        self.lblTwo.move(40, 40)
        self.lblTwo.resize(100, 100)

        self.btn = QPushButton("Update Labels", self)
        self.btn.move(40, 100)
        self.btn.clicked.connect(self.runThread)

    def runThread(self):
        data = Info()
        self.thread = QThread()
        self.worker = testThread(data)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.run)
        self.worker.finished.connect(self.evt_onFinished)
        self.worker.finished.connect(self.thread.quit)
        self.worker.finished.connect(self.worker.deleteLater)
        self.thread.finished.connect(self.thread.deleteLater)
        self.thread.start()

    def evt_onFinished(self, data):
        self.lblOne.setText(data.fname)
        self.lblTwo.setText(data.lname)


if __name__ == "__main__":
    app = QApplication(sys.argv)
    mnuMain = MainWindow()
    mnuMain.show()
    sys.exit(app.exec_())
  • Related