news 2026/5/30 10:25:06

PySide6从0开始学习的笔记(二十二) 几种封装信号传递内容的方法

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
PySide6从0开始学习的笔记(二十二) 几种封装信号传递内容的方法

Qt 框架的信号,它支持的类型范围为:

类别支持的类型示例
基础 Python 类型int, float, str, bool, list, dict, tupleSignal(int, str, list)
Qt 专用类型QWidget, QPoint, QColor, QSize 等Signal(QWidget, QPoint)
自定义类型自定义 Python 类(需注册)Signal(MyCustomClass)
无类型 / 任意类型objectSignal(object)

在实际工程中,经常会用到几个不同类型的变量组成的“复合”信号,比如视觉项目中,相机线程会将相机采集到的一幅图像的像素数据和采集的时间戳组合起来发给AI线程,AI线程对图像进行识别后再把标注了目标框的像素数据与识别结果以及时间戳组合起来发给UI线程以及后台保存线程,那么在定义信号的时候,当然可以使用列出信号元素的所有类型参数的方法,比如:

signal = Signal(str, str, float, QPixmap) # 时间戳,识别内容,置信度,显示像素

但是这种方法在使用的过程中并不直观,如上例中的2个str,它分别代表的含义在调用时并不明示。如果将信号传递的内容打包定义成一个类去创建、编辑和传递,在工程使用和移植代码的时候就很方便。

下面就列出几种定义信号传递的内容的常用方法:

一、将传递的内容定义为Qt的QObject基类

  • QObject:这是 Qt 中所有支持信号槽、属性系统、对象树管理的类的基类。
  • 意味着该类可以使用 Qt 的核心特性(如属性通知、父子对象管理等),而非普通 Python 类。
import sys from PySide6.QtCore import QObject, Signal from PySide6.QtGui import QPixmap from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout # 定义一个类,用来封装猫咪信息并作为信号发射 class CatSignal(QObject): def __init__(self, name: str, age: int, pixmap: QPixmap, parent=None): super().__init__(parent) self.name = name self.age = age self.pixmap = pixmap # 可选:添加数据验证,避免非法值 if not isinstance(name, str) or len(name) == 0: raise ValueError("猫咪名称必须是非空字符串") if not isinstance(age, int) or age < 0: raise ValueError("猫咪年龄必须是非负整数") if not isinstance(pixmap, QPixmap) or pixmap.isNull(): raise ValueError("图片必须是有效的 QPixmap") class MyWidget(QWidget): image_signal = Signal(CatSignal) def __init__(self): super().__init__() self.setWindowTitle("猫咪信息") layout = QVBoxLayout(self) self.label1 = QLabel(self) self.image_signal.connect(self.on_image_signal) self.label1.setScaledContents(True) self.label2 = QLabel(self) layout.addWidget(self.label1) layout.addWidget(self.label2) def on_image_signal(self, cat): self.label1.setPixmap(cat.pixmap) self.label2.setText(f"猫咪名字:{cat.name} , 猫咪年龄:{cat.age}") if __name__ == '__main__': app = QApplication(sys.argv) form = MyWidget() form.show() cat1 = CatSignal("三毛", 2, QPixmap("cat1.jpg")) # 创建信号 form.image_signal.emit(cat1) # 发射信号 sys.exit(app.exec())

二、将传递的内容定义为QGraphicsObject

如果在视图和场景体系中应用:

import sys from PySide6.QtCore import QObject, Signal, QRectF, Qt from PySide6.QtGui import QPixmap, QPainter from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout, QGraphicsObject, QGraphicsView, \ QGraphicsScene, QGraphicsPixmapItem class CatSignal(QGraphicsObject): def __init__(self, name: str, age: int, pixmap: QPixmap, parent=None): super().__init__(parent) self.name = name self.age = age self.pixmap = pixmap class MyWidget(QWidget): image_signal = Signal(CatSignal) def __init__(self): super().__init__() self.setWindowTitle("猫咪信息") self.layout = QVBoxLayout(self) self.view = QGraphicsView(self) self.scene = QGraphicsScene(self) self.view.setScene(self.scene) self.layout.addWidget(self.view) self.label = QLabel(self) self.label.setScaledContents(True) self.layout.addWidget(self.label) self.image_signal.connect(self.on_image_signal) def on_image_signal(self, cat): self.scene.clear() item_graphics = QGraphicsPixmapItem(cat.pixmap) self.scene.addItem(item_graphics) self.label.setText(f"猫咪名字:{cat.name} , 猫咪年龄:{cat.age}") self.layout.update() if __name__ == '__main__': app = QApplication(sys.argv) form = MyWidget() form.show() cat1 = CatSignal("MiMi", 2, QPixmap("cat1.jpg")) form.image_signal.emit(cat1) # 发射信号 sys.exit(app.exec())

三、将传递的内容定义为Python的object基类

  • 适用场景:最简单的场景,仅需封装属性,无额外需求。
  • 优势:轻量、无依赖,支持类型注解和数据验证。
  • 缺点:不具备Qt的Qobject的核心特性(如属性通知、父子对象管理等)。
class CatSignal(object): def __init__(self, name: str, age: int, pixmap: QPixmap): super().__init__() self.name = name self.age = age self.pixmap = pixmap # 可选:添加数据验证,避免非法值 if not isinstance(name, str) or len(name) == 0: raise ValueError("猫咪名称必须是非空字符串") if not isinstance(age, int) or age < 0: raise ValueError("猫咪年龄必须是非负整数") if not isinstance(pixmap, QPixmap) or pixmap.isNull(): raise ValueError("图片必须是有效的 QPixmap")

四、使用dataclasses.dataclass

  • 适用场景:需要自动生成__init____repr____eq__等方法,简化数据类代码。
  • 核心优势:减少重复代码,支持默认值、类型检查、冻结(不可修改)等特性。
from dataclasses import dataclass, field @dataclass(frozen=True) # frozen=True:实例不可修改(只读数据) class CatSignal: name: str # 必选属性 pixmap: QPixmap = field(compare=False) # 比较时忽略 pixmap(避免大对象比较) age: int = field(default=0) # 可选属性,默认值 0 # 可选:字段验证(通过 __post_init__ 实现) def __post_init__(self): if len(self.name) == 0: raise ValueError("名称不能为空") if self.pixmap.isNull(): raise ValueError("无效图片") if self.age < 0: raise ValueError("年龄不能为负")

五、使用typing.NamedTuple

  • 适用场景:需要轻量级、只读的数据容器,支持 tuple 特性(可迭代、哈希)。
  • 优势:比dataclass更轻量,天然支持解构(name, age = cat)。
import sys from dataclasses import dataclass, field from PySide6.QtCore import QObject, Signal from PySide6.QtGui import QPixmap from PySide6.QtWidgets import QApplication, QWidget, QLabel, QVBoxLayout # 定义一个类,用来封装猫咪信息并作为信号发射 from typing import NamedTuple class CatSignal(NamedTuple): name: str pixmap: QPixmap age: int = 0 class MyWidget(QWidget): image_signal = Signal(CatSignal) def __init__(self): super().__init__() self.setWindowTitle("猫咪信息") layout = QVBoxLayout(self) self.label1 = QLabel(self) self.image_signal.connect(self.on_image_signal) self.label1.setScaledContents(True) self.label2 = QLabel(self) layout.addWidget(self.label1) layout.addWidget(self.label2) def on_image_signal(self, cat): self.label1.setPixmap(cat.pixmap) self.label2.setText(f"猫咪名字:{cat.name} , 猫咪年龄:{cat.age}") if __name__ == '__main__': app = QApplication(sys.argv) form = MyWidget() form.show() # 使用(实例不可修改) cat1 = CatSignal("咪酱", QPixmap("cat1.jpg"), 3) print(cat1.name) name, pixmap, age = cat1 # 解构 print(name, age) form.image_signal.emit(cat1) # 发射信号 sys.exit(app.exec())

六、数据库储存场景

  • 若需将数据通过信号发射到数据库线程,存入数据库(如 SQLite、MySQL),可继承 ORM 框架的基类:
    • SQLAlchemy:declarative_base()
    • Django ORM:models.Model
  • 示例(SQLAlchemy)
from sqlalchemy.ext.declarative import declarative_base from sqlalchemy import Column, String, Integer, LargeBinary from PyQt5.QtGui import QPixmap import io Base = declarative_base() class CatDB(Base): __tablename__ = "cats" # 数据库表名 id = Column(Integer, primary_key=True, autoincrement=True) name = Column(String(50), nullable=False) # 名称(非空) age = Column(Integer, default=0) # 年龄 pixmap_data = Column(LargeBinary) # 图片二进制数据(QPixmap 无法直接存数据库) # 转换 QPixmap 为二进制(存库) def set_pixmap(self, pixmap: QPixmap): buffer = io.BytesIO() pixmap.save(buffer, "PNG") self.pixmap_data = buffer.getvalue() # 从二进制转换为 QPixmap(读库) def get_pixmap(self) -> QPixmap: buffer = io.BytesIO(self.pixmap_data) return QPixmap.fromImageReader(buffer)

七、对比

需求场景推荐基类核心优势
Qt 图形场景(GraphicsScene)QGraphicsObject、QObject可以使用 Qt 的核心特性,QGraphicsObject支持绘图、碰撞检测、动画
仅封装数据(轻量)object无依赖,最简单
数据类(自动生成方法)dataclasses.dataclass简化代码,支持验证、默认值
只读数据容器typing.NamedTuple轻量,支持解构、哈希
数据库存储SQLAlchemyBase/DjangoModelORM 映射,直接操作数据库

总结

  1. 优先选纯 Python 基类:若信号传递的内容仅为数据载体,dataclass(灵活)或NamedTuple(只读)是最优选择,轻量且无 Qt 耦合;
  2. Qt 视图场景:继承QAbstractItemModel子类,享受 Qt 模型视图的自动同步特性;
  3. 图形 / 信号槽场景:继承QGraphicsObject或只保留QObject,利用 Qt 的图形 / 信号机制;
  4. 数据库 / 序列化场景:使用 ORM 或序列化库的基类,简化数据持久化。

根据实际需求(是否需要 UI 绑定、数据库存储、只读特性等)选择即可,大多数场景下dataclasses.dataclass是兼顾简洁性和功能性的首选。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/28 15:01:44

JSON格式化零基础入门:5分钟学会标准写法

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个交互式JSON学习工具&#xff0c;功能包括&#xff1a;1. JSON语法实时检查 2. 错误高亮和修正建议 3. 格式化前后对比视图 4. 常见错误示例库 5. 渐进式难度练习。要求界面…

作者头像 李华
网站建设 2026/5/27 4:23:22

智能家居中WIFI与蓝牙冲突的5个真实案例及解决方案

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个智能家居设备冲突诊断工具。输入智能家居设备清单&#xff08;如智能音箱、智能灯泡、路由器等&#xff09;&#xff0c;自动分析可能存在的WIFI/蓝牙冲突风险&#xff0c…

作者头像 李华
网站建设 2026/5/29 11:58:55

1小时快速验证:用YOLOv8构建目标检测原型系统

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 开发一个快速原型系统&#xff0c;使用YOLOv8实现&#xff1a;1) 支持摄像头/图片实时检测 2) 简易标注工具快速创建小样本数据集 3) 迁移学习快速微调 4) 实时性能监测 5) 一键导…

作者头像 李华
网站建设 2026/5/23 8:02:21

HTML页面嵌入WebSocket实时接收VibeVoice生成进度

HTML页面嵌入WebSocket实时接收VibeVoice生成进度 在播客制作、有声书生产甚至虚拟教学场景中&#xff0c;用户不再满足于“输入文本、等待输出”的黑盒式语音合成体验。他们希望看到过程——谁在说话&#xff1f;进度到哪了&#xff1f;还要等多久&#xff1f;这种对过程可见性…

作者头像 李华
网站建设 2026/5/21 10:55:24

工业控制模块PCB绘制可制造性设计指南

工业控制模块PCB设计&#xff1a;从“能用”到“耐用”的可制造性实战指南在工厂的自动化产线上&#xff0c;一个小小的远程I/O模块可能正默默控制着几十台电机的启停&#xff1b;在高温高湿的配电柜里&#xff0c;一块PLC扩展板连续运行十年也不允许宕机。这些看似普通的工业控…

作者头像 李华
网站建设 2026/5/20 23:55:44

C# HttpClient异步请求VibeVoice API提高响应速度

C# HttpClient异步请求VibeVoice API提高响应速度 在播客制作、有声书生成和虚拟访谈等场景中&#xff0c;用户对语音合成的自然度与交互真实感要求越来越高。传统的TTS系统往往只能处理短文本、支持一到两个说话人&#xff0c;且角色切换生硬&#xff0c;难以满足长时多角色对…

作者头像 李华