PyQt5中如何从QThread线程返回更新后的dataclass数据类实例
PyQt5 QThread 返回dataclass实现方案
可行性说明
完全可以实现,无法生效的核心原因是自定义信号的参数类型指定错误,以及信号绑定、接收逻辑存在疏漏。
现有代码错误点梳理
- 自定义
finished信号未声明参数类型:当前定义的是无参数信号finished = pyqtSignal(),但run方法里emit时传入了self.data参数,类型不匹配无法传递。之前尝试的pyqtSignal(dataclass)、pyqtSignal(class)写法都是错误的,需要直接传入自定义的dataclass类名info作为参数类型。 - 信号绑定逻辑错误:绑定了
QThread自带的finished信号来触发更新操作,而线程自带的finished信号是无参数的,应该绑定自定义的worker的finished信号来接收传递的dataclass实例。 - 方法入参不匹配:
evt_onFinished方法未定义接收dataclass参数的入参,绑定信号时传入的data变量属于未定义变量。 - 缺失标签更新逻辑:
evt_onFinished方法没有写更新界面标签的具体代码。
修复后的完整代码
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): # 自定义信号指定参数类型为自定义的Info dataclass 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" # 传递更新后的dataclass实例 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,30) self.lblTwo = QLabel("Old Text", self) self.lblTwo.move(40, 60) self.lblTwo.resize(100,30) 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) # 绑定自定义finished信号的处理逻辑 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, updated_data): "Update the labels with the information from the returned/updated dataclass" self.lblOne.setText(updated_data.fname) self.lblTwo.setText(updated_data.lname) if __name__ == "__main__": app = QApplication(sys.argv) mnuMain = MainWindow() mnuMain.show() sys.exit(app.exec_())
核心改动说明
- 修改自定义信号声明为
finished = pyqtSignal(Info),明确指定传递参数为自定义的Info dataclass类型 - 调整信号绑定逻辑,直接将worker的finished信号绑定到evt_onFinished方法,自动传递更新后的dataclass实例
- 完善evt_onFinished方法的入参和标签更新逻辑
- 调整了标签的高度避免文字重叠
内容的提问来源于stack exchange,提问作者ProgramMasher
相关产品推荐
相关产品推荐

