谈谈Qt信号与槽

2023-11-19

关于Qt信号与槽

Qt信号与槽本质类似观察者模式

观察者模式(Observer Pattern)
定义对象间的一种一对多依赖关系,使得每当一个对象状态发生改变时,其相关依赖对象皆得到通知并被自动更新。观察者模式又叫做发布-订阅(Publish/Subscribe)模式、模型-视图(Model/View)模式、源-监听器(Source/Listener)模式或从属者(Dependents)模式。

但是不能因为Qt信号与槽,误解了观察者模式,观察者模式处理多对多还有些思路需要理清。

Qt本身就是基于C++开发而来,在没有信号与槽的时代,C++对象之间的交互需要通过回调函数来实现。

回调函数
使用某对象时,用指针指向另一个对象的函数,这个函数就是回调函数
回调函数的速度要优于信号与槽。
在某个对象被多个对象关联通信的时候,此时这些被关联的对象需要存储在一个容器中,维护容器会使得代码扩展和优化效率低下。

信号与槽工作机制

信号与槽基于元对象来实现的,一下介绍的是旧写法。

connect(sender, SIGNAL(a()), receiver, SLOT(b()));

通过以上connect连接可知,sender是通知者,receiver是观察者,而中间对象是Qt的元对象,sender对象和receiver对象本身也含有Qt的元对象,其中并含有signals信号函数和slots槽函数,SIGNAL和SLOT都是宏,将a和b函数转字符串处理,存储到对应元对象字符串表中,connect函数通过查找元对象中的字符串表,获取到对应的sigId和sltId,然后保存到一个map中,emit宏定义是空,因此emit sigXX()实际上只是执行sigXX(),sigXX()函数会去查询map中对应的receiver对象和sltId,receiver元对象也存在一个槽函数列表,会通过遍历槽函数列表找到sltId去执行指定的槽函数。

使用信号与槽功能需要开启在类声明前使用Q_OBJECT()宏来开启元对象功能。
使用元对象系统的3个条件:
1.只有QObject派生类才可以使用元对象系统特性。
2.在类声明前使用Q_OBJECT()宏来开启元对象功能。
3.使用Moc工具为每个QObject子对象自动生成必要的代码来实现元对象特性。

信号与槽优缺点

相比回调函数,运行性能会低一些,相比直接调用函数会慢很多。
总结便是:
1.发送者需要定位接受信号的对象。
2.需要整个工作过程所有关联,可能是多对多。
3.编组/解组传递的参数。
4.在多线程中可能存在排队情况。

说了缺点,那么为什么还需要信号与槽,下面说说信号与槽的优点:
1.类型安全:槽函数的参数类型和个数必须和信号的参数类型和个数一一对应
2.降低Qt对象的耦合度:在使用过程中,信号对象不关心哪个对象的槽函数接收它的信号,也不关心它的信号是否被接受到,反之同样道理,使用过程哪怕关联对象被释放掉了,也不担心崩溃问题。
3.一个信号可以对应多个槽函数,一个槽函数也可以对应多个信号。
4.信号与槽新写法支持匿名Lambda表达式,写法更简单。
对比观察者设计模式和回调函数,使用方便。

关于多线程下的信号与槽

这里需要介绍信号与槽connect函数里第五个参数了。
1.Qt::AutoConnection:
默认值,使用这个值则连接类型会在信号发送时决定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection类型。如果接收者和发送者不在一个线程,则自动使用Qt::QueuedConnection类型。

2.Qt::DirectConnection:
槽函数会在信号发送的时候直接被调用,槽函数运行于信号发送者所在线程。效果看上去就像是直接在信号发送位置调用了槽函数。这个在多线程环境下比较危险,可能会造成奔溃。

3.Qt::QueuedConnection:
槽函数在控制回到接收者所在线程的事件循环时被调用,槽函数运行于信号接收者所在线程。发送信号之后,槽函数不会立刻被调用,等到接收者的当前函数执行完,进入事件循环之后,槽函数才会被调用。多线程环境下一般用这个。

4.Qt::BlockingQueuedConnection:
槽函数的调用时机与Qt::QueuedConnection一致,不过发送完信号后发送者所在线程会阻塞,直到槽函数运行完。接收者和发送者绝对不能在一个线程,否则程序会死锁。在多线程间需要同步的场合可能需要这个。

5.Qt::UniqueConnection:
这个flag可以通过按位或(|)与以上四个结合在一起使用。当这个flag设置时,当某个信号和槽已经连接时,再进行重复的连接就会失败。也就是避免了重复连接。

关于信号与槽新旧写法

1.将signal和slot作为字符串处理

QMetaObject::Connection connect(const QObject *, const char *, const QObject *, const char , Qt::ConnectionType); 
//示例
connect(sender, SIGNAL(a()), receiver, SLOT(b()));

2.用函数地址作为信号或者槽传入,在编译器便可以获到类型检查

QMetaObject::Connection connect(const QObject *, const QMetaMethod &, const QObject *, const QMetaMethod &,Qt::ConnectionType);
//示例
connect(sender, &QPushButton::clicked, this, &QWidget::close);

3.此写法就是第二种写法,可以省去this指针

QMetaObject::Connection connect(const QObject *, const char *,const char *,Qt::ConnectionType) const; 
//示例
connect(sender, &QPushButton::clicked, &QWidget::close);

4.同一个类中成员函数之间关联,当成员函数没有重载时,可以直接使用

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,const QObject *, PointerToMemberFunction,Qt::ConnectionType);
connect(this,&MainWindow::send,this,&MainWindow::close);

5.槽函数为Functor 类型。这个类型可以接受 static 函数、全局函数以及 Lambda 表达式.

QMetaObject::Connection connect(const QObject *, PointerToMemberFunction,Functor);
//示例
connect(sender, &QPushButton::clicked, this, [=](){
	XXX();
});

关于信号与槽新旧写法区别

之前的旧写法(SIGNAL和SLOT)需要注意槽函数必须写到其元对象slots下,而新写法连接的槽函数可以为任意的成员函数,普通全局函数,静态函数。
旧写法中信号如果有参数,必须写上,不能省去。
旧写法中函数不可以省去()。
新写法需要注意重载问题
举例说明

connect(sender, &QPushButton::clicked, &QTimer::start);

QTimer类中存在两个start函数

start(int)
start()

这时候编译器无法确定使用哪一个,因此需要我们确认使用哪一个
解决方法有以下
1.强制类型转换操作符static_cast
编译器隐式执行的任何类型转换都可以由static_cast来完成
需要用到匿名函数指针

typedef void (QTimer:: *timer)(void);
connect(sender, &QPushButton::clicked, static_cast<timer>(&QTimer::start));

2.QOverload类
该函数返回一个指向重载函数的指针,其中的模板参数是重载函数参数类型的列表

connect(sender, &QPushButton::clicked, QOverload<>::of(&QTimer::start));
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

谈谈Qt信号与槽 的相关文章

  • Qt 人工鼠标点击无法正常工作

    小玩具应用程序可以在这里找到 http gist github com 517445 http gist github com 517445 我正在尝试将人工鼠标事件发送到小部件 我使用QApplication sendEvent为此 接下
  • 在 Qt 服务器上验证用户身份

    我正在尝试使用 C QtTcpSocket 为个人项目 多人国际象棋游戏 实现身份验证系统 我的朋友建议了一种验证用户的方法 但我想问是否有更简单或更好的方法 来自 Python 背景 做这个项目主要是为了加深对 C 的理解 我将发布我朋友
  • 用 C++/Qt 编写的程序中的 RTF / doc / docx 文本提取

    我正在写一些程序Qt https en wikipedia org wiki Qt 28software 29 C 我需要从中读取文本微软Word https en wikipedia org wiki Microsoft Word RTF
  • QStyledItemDelegate 绘制自定义小部件失败

    在我的一个项目中 我使用的是QTableWidget为了显示一些复杂的计算结果 为了提高表格的可读性 我需要在单个表格单元格内显示两个对齐的值 后来我想通过使用颜色或箭头等来进一步自定义小部件 为此我源自QStyledItemDelegat
  • QT:删除QGridLayout中QLabel之间的空格

    我将一些具有不同颜色的 QLabels 添加到 QGridLayout 作为 QWidget 的布局 现在我在每个 Qlabel 与下一个 Qlabel 之间有一个间距 我想将其删除 我尝试将标签的边距设置为 0 将 GridLayout
  • Qt 为什么使用 QString::number() 而不是 QLocale().toString()?

    我正在开发的应用程序将在许多国家推出 并且需要支持他们的语言 我一直在回顾我的代码并替换以下每个实例 QString number and QString toDouble with QLocale toString and QLocale
  • 使用 CMake 编译时更改头文件位置会导致缺少 vtable 错误

    对于一个大型 C 项目 我需要从 qmake 过渡到 CMake 但是在处理一个玩具示例时 我遇到了一些我不理解的行为 示例代码具有单个头文件 当该头文件移动到子目录中时 我收到 MainWindow 类缺少 vtable 的错误 CMak
  • QMainWindow 上的 Qt 布局

    我设计了一个QMainWindow with QtCreator s设计师 它由默认的中央小部件 aQWidget 其中包含一个QVBoxLayout以及其中的所有其他小部件 现在我想要的一切就是QVBoxLayout自动占据整个中央小部件
  • C++ SQL 查询构建库

    我正在寻找一个提供与 c SelectQueryBuilder 库类似功能的 c 库 http www codeproject com Articles 13419 SelectQueryBuilder Building complex a
  • Qt:不完整类型和前向声明的使用无效

    我有一些误解 A h ifndef A H define A H include B h class A public B Q OBJECT public A endif A cpp include A h A A B ui gt blan
  • Qt中Q_PROPERTY的意义是什么?

    我无法理解 Q PROPERTY 的用法 Q PROPERTY 如何帮助程序具有防御性 它是干什么用的 我看过这个论坛 但确实无法应用 我已经理解了这个例子 但不明白它的用法 这是一个例子 我能从中得到什么 我知道阅读将赋予只读特权 wri
  • Qt中用于线程间通信的类设计

    问题陈述 用相机跟踪物体并相应地移动相机的方位角和仰角 Process 相机获取物体的图像 处理相机的每一帧以查找物体 应该被跟踪 并将每帧中生成的信息传递给机械设备 万向节 以平移和倾斜方式移动摄像机 Design 主 Gui 在一个线程
  • 如何将自定义 Qt 类型与 QML 信号一起使用?

    我在 Qt 5 2 qml 应用程序中创建了一个自定义类型 class Setting public QObject Q OBJECT Q PROPERTY QString key READ key WRITE setKey Q PROPE
  • 如何在Android中使用QML - QWebView

    我想在 Android 中部署一个 YouTube 应用程序 但它只能在我的电脑上运行 在安卓上不起作用 它不加载任何视频 问题仅出在 QWebView 上 我使用了与此类似的代码 http doc qt io archives qt 5
  • 为什么 QT 设计器重新调整大小或不允许我缩小或展开小部件或按钮?

    很多时候 在使用 QT 设计器时 我发现自己需要通过缩小或扩展来调整事物的大小 每当我尝试这样做时 程序都不允许我这样做 而只是恢复到将对象放置在窗口中时给我的原始默认大小 无论我的布局如何 为什么要这样做 是否有可能改变这一点 以便我可以
  • 如何将 QFile 与 std::iostream 一起使用?

    是否可以像 std iostream 一样使用 QFile 我很确定那里一定有一个包装纸 问题是在哪里 我有另一个库 它需要 std istream 作为输入参数 但在我的程序中 此时我只有一个 QFile 我使用以下代码提出了自己的解决方
  • Qt - 如何使用 QNetworkAccessmanager 获取响应文本

    这是我的代码 Widget Widget manager new QNetworkAccessManager this connect manager SIGNAL finished QNetworkReply this SLOT repl
  • 使用 QWT 构建时出错

    我收到一个错误 undefined reference to QwtPlot QwtPlot QWidget 当我尝试构建我的项目时 即使设置中一切看起来都很好 在我的 CmakeLists txt 中我有 include director
  • 一个具有完全透明背景的qt小部件

    我需要创建一个 qt 小部件 它将充当其他一些小部件的父级 并对它们进行排序 现在的问题是如何使其背景完全透明 我想这样做 struct Imp Imp QWidget parent thisWidget new QWidget paren
  • QWebEngineView 在 load() 或 page() 方法上崩溃

    我正在致力于将 Qt 5 5 QWebView 项目移植到 Qt 5 6 测试版 QWebEngine 我已经阅读了移植指南here https wiki qt io Porting from QtWebKit to QtWebEngine

随机推荐

  • Unity动画系统详解5:BlendTree混合树是什么?

    摘要 Animator中有一个功能 用来解决多个动画之间的混合 经常用于移动动画之间的混合 这个功能叫做BlendTree 混合树 洪流学堂 让你快人几步 你好 我是跟着大智学Unity的萌新 我叫小新 这几周一起来复 yu 习 xi 动画
  • cl : 命令行 warning D9002:忽略未知选项“ /NODEFAULTLIB:library ”

    前言 cl 命令行 warning D9002 忽略未知选项 NODEFAULTLIB library 原因 一下引用 連結器工具警告 LNK4098 执行运行时程序库现在包含指示词 以防止混合不同的类型 如果您尝试在相同的程序中使用不同类
  • leetcode刷题(7)二叉树(1)

    哈喽大家好 这是我leetcode刷题的第七篇 这两天我将更新leetcode上关于二叉树方面的题目 如果大家对这方面感兴趣的话 欢迎大家持续关注 谢谢大家 那么我们就进入今天的主题 文章目录 1 二叉树的前序遍历 题目要求 示例 做题思路
  • RESTful-RESTful GET,如果存在大量参数,是否有必要变通一下?

    问题 比如设计一个GET接口 用来获取满足条件的商品 GET shop 1 goods 参数可能是五花八门的 name create time description status owner 通常这种情况 如果不考虑RESTful 就会设
  • C++工程师复习题

    一 auto ptr 类使用必须满足下列限制 1 不要使用 auto ptr 对象保存指向静态分配对象的指针 2 不要使用两个 auto ptrs 对象指向同一对象 3 不要使用 auto ptr 对象保存指向动态分配数组的指针 4 不要将
  • Vulkan再探(7):纹理贴图

    08 20 2020 文章目录 纹理贴图 Texture Mapping 纹理属性 加载图片 临时缓冲区储存图片信息 生成贴图等级 生成图像和存储空间 难点 传输数据 图解 拷贝缓冲区到图像 创建采样器 创建图像视图 创建组合图像采样器描述
  • Vulkan 绘制显示设计

    背景 众所周知 Vulkan是个跨平台的图形渲染API 为了友好地支持跨平台 Vulkan自然也抽象出了很多接口层去对接各个操作系统 抹平系统间的差异 Swap Chains即为WSI 其本质上是一种图像队列 此队列会按顺序依次将队列中的若
  • 《深入理解java虚拟机》 第二章

    1 运行数据区域 1 1线程私有 1 1 1 程序计数器 字节码解释器通过程序计数器里的数值来寻找下一条要执行的指令 执行native方法无程序计数器值 无OOM 1 1 2 java虚拟机栈 每一个方法运行时都会建立一个栈帧 栈帧用来存储
  • 深度学习中卷积和池化的一些总结

    最近完成了hinton的深度学习课程的卷积和池化的这一章节了 马上就要结束了 这个课程的作业我写的最有感受 待我慢慢说来 1 里面有几个理解起来的难点 一个是卷积 可以这么来理解 这幅图是对一个5 5的矩阵A进行3 3的矩阵B的卷积 那么就
  • 大数据分析系统

    1 概念 分类 数据分析系统的主要功能是从众多外部系统中 采集相关的业务数据 集中存储到系统的数据库中 系统内部对所有的原始数据通过一系列处理转换之后 存储到数据仓库的基础库中 然后 通过业务需要进行一系列的数据转换到相应的数据集市 供其他
  • LeetCode刷题——剑指offer位运算题目汇总(包含快速乘、快速幂、二进制加法)

    剑指offer位运算题目汇总 剑指 Offer II 001 整数除法 剑指 Offer II 002 二进制加法 剑指 Offer II 003 前 n 个数字二进制中 1 的个数 剑指 Offer II 004 只出现一次的数字 剑指
  • 手摸手,带你用vue撸后台 系列四(vueAdmin一个极简的后台基础模板)(好文章!!)

    转载自 原文格式清晰 https juejin im post 6844903486241374221 完整项目地址 vue element admin 系列文章 手摸手 带你用 vue 撸后台 系列一 基础篇 手摸手 带你用 vue 撸后
  • 【CSDN】删除文章后,浏览量会减少吗?了解软删除和硬删除

    hello 我是小索奇 如果你也在博客写作的话 有没有考虑到一个问题 文章删除后 浏览量会减少吗 下面就给大家阐述一下 当在CSDN中删除已发布的文章后 该文章的浏览量统计会有以下情况 软删除状态的文章 浏览量统计会保留 不会下降或者重置
  • html+css+javascript 之间的关系与作用

    三者间的关系 一个基本的网站包含很多个网页 一个网页由 html css 和 javascript 组成 html 是主体 装载各种 dom 元素 css 用来装饰 dom 元素 javascript 控制 dom 元素 用一扇门比喻三者间
  • springboot多模块打包配置问题

    工程案例结构 baidu 聚合过程 baidu web 子模块web工程 baidu service 子模块 baidu config 子模块配置工程 注意事项 配置步骤 1 baidu 聚合工程 工程下的 pom xml 文件案列如下
  • 【云原生之k8s】K8s 管理工具 kubectl 详解(二)

    K8S模拟项目 Kubectl是管理k8s集群的命令行工具 通过生成的json格式传递给apiserver进行创建 查看 管理的操作 帮助信息 root localhost bin kubectl help kubectl controls
  • mysqlbinglog基于即时点还原

    mysqlbinglog基于即时点还原 mysqlbinlog介绍 要想从二进制日志恢复数据 你需要知道当前二进制日志文件的路径和文件名 一般可以从选项文件 即my cnf or my ini 取决于你的系统 中找到路径 mysql5 7开
  • SAR成像系列:【3】合成孔径雷达(SAR)的二维回波信号与简单距离多普勒(RD)算法 (附matlab代码)

    合成孔径雷达发射信号以线性调频信号 LFM 为基础 目前大部分合成孔径雷达都是LFM体制 为了减轻雷达重量也采用线性调频连续波 FMCW 体制 为了获得大带宽亦采用线性调频步进频 FMSF 体制 1 LFM信号 LFM的主要特点在于可以使载
  • 操作系统内存管理——分区、页式、段式、段页式管理

    1 内存管理方法 内存管理主要包括虚地址 地址变换 内存分配和回收 内存扩充 内存共享和保护等功能 2 连续分配存储管理方式 连续分配是指为一个用户程序分配连续的内存空间 连续分配有单一连续存储管理和分区式储管理两种方式 2 1 单一连续存
  • 谈谈Qt信号与槽

    关于Qt信号与槽 Qt信号与槽本质类似观察者模式 观察者模式 Observer Pattern 定义对象间的一种一对多依赖关系 使得每当一个对象状态发生改变时 其相关依赖对象皆得到通知并被自动更新 观察者模式又叫做发布 订阅 Publish