news 2026/5/1 21:00:12

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/1 4:53:54

5分钟快速验证:JLINK接口连接方案原型

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个JLINK连接验证原型生成器&#xff0c;用户输入或选择目标板信息后&#xff0c;自动生成&#xff1a;1&#xff09;最小测试电路图&#xff08;含保护电路&#xff09;2&am…

作者头像 李华
网站建设 2026/4/30 16:08:53

如何用AI快速搭建数据分析平台:METABASE实战

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 创建一个基于METABASE的数据分析平台&#xff0c;支持连接MySQL、PostgreSQL等常见数据库。自动生成数据模型和可视化仪表板&#xff0c;包含折线图、柱状图、饼图等常见图表类型。…

作者头像 李华
网站建设 2026/4/30 22:48:04

完整指南:搭建第一个数字频率计电路

从零开始搭建你的第一台数字频率计&#xff1a;不只是“数脉冲”那么简单你有没有试过用示波器看一个信号&#xff0c;想确认它的频率是多少&#xff1f;眼睛盯着波形来回数周期——“一、二、三……这个是第几个了&#xff1f;”——结果一走神又得重来。如果有个小设备能直接…

作者头像 李华
网站建设 2026/5/1 5:56:58

cpp-httplib大文件传输性能调优:从问题诊断到实战验证

cpp-httplib大文件传输性能调优&#xff1a;从问题诊断到实战验证 【免费下载链接】cpp-httplib A C header-only HTTP/HTTPS server and client library 项目地址: https://gitcode.com/GitHub_Trending/cp/cpp-httplib 在当今数据驱动的应用场景中&#xff0c;cpp-htt…

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

网盘直链下载助手解析蓝奏云分享链接获取VibeVoice资源

网盘直链下载助手解析蓝奏云分享链接获取VibeVoice资源 在AI语音技术飞速演进的今天&#xff0c;我们早已不再满足于“把文字读出来”这种基础能力。无论是播客创作者希望自动生成双人对谈内容&#xff0c;还是游戏开发者需要为NPC构建富有情绪张力的对话系统&#xff0c;传统T…

作者头像 李华
网站建设 2026/5/1 5:56:20

10分钟用Python构建MVP:快马平台原型开发指南

快速体验 打开 InsCode(快马)平台 https://www.inscode.net输入框内输入如下内容&#xff1a; 快速开发一个Python实现的待办事项应用原型&#xff0c;要求&#xff1a;1) 添加任务 2) 标记完成 3) 删除任务 4) 按状态筛选 5) 数据持久化到JSON文件。界面使用简单的命令行交互…

作者头像 李华