Qt之信号和槽的机制

前言       

        在 C++ 中,对象与对象之间产生联系要通过调用成员函数的方式。但是在 Qt中,Qt提供了一种新的对象间的通信方式,即信号和槽机制。在GUI编程中,通常希望一个窗口部件的一个状态的变化会被另一个窗口部件知道,为了实现这种效果且取代老式的回调函数,信号和槽机制应运而生,Qt通过 QObject 提供信号和槽的功能。
        信号和槽的核心原理很简单,当某个事件发生之后,如按钮检测到自己被单击了一下,它就会广播出一个信号。如果有对象对这个信号感兴趣,就使用连接函数,将想要处理的信号和自己的一个函数(称为槽函数)进行绑定并处理这个信号。也就是说,当信号被发出时,与之连接的槽即函数会自动被回调。


信号和槽的使用 

        槽的本质就是类的成员函数,其参数可以是任意类型,可以是虚函数,可以被重载。槽通常和信号连接在一起,当信号被发出时,与这个信号连接的槽函数就会被调用,其语法如下。

connect(sender, SIGNAL(signal), receiver, SLOT(slot));

具体参数如下:

  • sender:发出信号的对象。
  • signal:发送对象发出的信号。
  • receiver:接收信号的对象。
  • slot:接收对象在接收到信号之后所需要调用的函数。

        参数中的 sender 就是指向发送信号的对象的指针,receiver 是指向包含槽函数的对象的指针。signal是被发送的信号,slot是接收信号后调用的槽函数,均为不带参数的函数名。SIGNAL()和SLOT()会将其参数转换为字符串,即将函数名转换为字符串,将这个字符串传入 connect()中。

信号和槽的连接比较随意,一个信号可以连接多个槽。
connect(sender, SlGNAL(sianal), receiverA, SLOT(slotA));
connect(sender, SlGNAL(signal), receiverB, SLOT(slotB));也可以多个信号连接同一个槽。
connect(senderA, SIGNAL(signalA), receiver, SLOT(slot));
connect(senderB, SlGNAL(signalB), receiver, SLOT(slot));一个信号还可以连接另外一个信号。
connect(sender, SIGNAL(signalA), receiver, SlGNAL(signalB));当 sender对象发送信号给signalA时,触发receiver对象发送信号给signalB。同时,信号和槽之间的连接可以被移除。
disconnect(sender, SlGNAL(signal),receiver, SLOT(slot));

 Qt 信号和槽机制的优缺点如下:

  • Ot的信号和槽机制的引用可减少程序员编写的代码量。
  • Qt的信号可以对应多个槽(它们的调用顺序随机),也可以多个槽映射一个信号
  • Qt的信号和槽的建立与解除绑定十分自由。
  • 信号和槽同真正的回调函数比起来,时间的耗损还是很大的,在嵌入式实时系统中应当慎用。
  • 信号和槽的参数限定很多,如不能携带模板类参数、不能出现宏定义等。

 用一个例子来解释一下信号和槽的机制:

 新建一个基类 QWidget的 Qt 图形应用项目。

 在widgt.h文件中:

#ifndef WIDGT_H
#define WIDGT_H
#include<QPushButton>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class widgt; }
QT_END_NAMESPACE
class widgt : public QWidget
{Q_OBJECT//只有继承了QObject类的类,才具有信号和槽;//宏QOBJECT是任何实现信号、槽或属性的强制性要求
public:widgt(QWidget *parent = nullptr);~widgt();
private:Ui::widgt *ui;QPushButton button;
};
#endif // WIDGT_H

在widgt.cpp文件中:

#include "widgt.h"
#include "ui_widgt.h"
widgt::widgt(QWidget *parent): QWidget(parent), ui(new Ui::widgt)
{this->resize(200,200);//修改默认的窗口尺寸button.setParent(this);// 绑定窗口和按钮button.setText("关闭窗口");// 按钮框中文本button.move(48,64);// 定义按钮的位置,以左上角为原点,px 为单位connect(&button,&QPushButton::pressed,this,&widgt::close);
}
widgt::~widgt()
{delete ui;
}

在main.cpp文件中:

#include "widgt.h"
#include <QApplication>
int main(int argc, char *argv[])
{QApplication a(argc, argv);widgt w;w.show();return a.exec();
}

        在这些代码中,button是信号的发送方;信号为QPushButton基类定义的pressed信号;信号接收方为 widgt w,即在构造函数中写为 this;槽函数为基类QWidget定义的 close()函数。这样,在单击“close”按钮时,该按钮 button会发送一个pressed信号,pressed信号会触发w中继承的 close()函数,实现结束程序的功能。 


自定义信号和槽函数

         connect()函数可用来连接系统提供的信号和槽。但是,Qt的信号和槽机制并不是仅能使用系统提供的那部分,程序员也可设计自己的信号和槽。

        首先,创建一个基于基类 QWidget的 Qt图形应用项目,添加一个新的类,类名为“Widget”继承于 Qt 的基类 QWidget。

 在widgt.h文件中:

#ifndef WIDGET_H
#define WIDGET_H
#include <QLabel>
#include <QPushButton>
#include <QWidget>
QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE
class Widget : public QWidget
{Q_OBJECT
public:Widget(QWidget *parent = nullptr);void MySlot();//定义~Widget();
private:Ui::Widget *ui;QPushButton button;QLabel label;
};
#endif // WIDGET_H

 在widgt.cpp文件中:

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent): QWidget(parent), ui(new Ui::Widget)
{this->resize(240,320);button.setParent(this);button.move(40,50);button.setText("更换内容");label.setParent(this);label.move(40,100);label.setText("更换前");connect(&button,&QPushButton::pressed,this,&Widget::MySlot);
}
void Widget::MySlot()
{label.setText("更换后");
}
Widget::~Widget()
{delete ui;
}

在main.cpp文件中

#include "widget.h"
#include <QApplication>
int main(int argc, char *argv[])
{QApplication a(argc, argv);Widget w;w.show();return a.exec();
}

结果:

 


自定义信号和槽函数的要点

自定义槽函数要点如下。

  • 槽函数可以传入参数,但没有返回值。
  • 在 Qt5 中,任何成员函数、静态成员函数、全局函数及 Lambda 表达式都可以作为槽函数。与信号函数不同,槽函数必须自己完成实现代码。槽函数就是普通的成员函数,因此也会受到public、private 等访问控制关键字的影响。( 如果信号是私有的,这个信号就不能在类的外面连接,而类中本来就可以直接传递,因此这种限制也就没有任何意义。)

 自定义信号和槽需要注意的事项有以下几个。

  • 发送者和接收者都需要 QObject的派生类(当然,槽函数是全局函数、Lambda 表达式等无须接收者的时候除外 )。
  • 使用 signals 标记信号,信号是一个函数声明,返回 void,不需要实现函数代码。
  • 使用 emit 在恰当的位置发送信号。
  • 可以在 main.cpp 中使用QObject::connect()函数连接信号和槽函数。
  • 任何成员函数、静态成员函数、全局函数及Lambda 表达式都可以作为槽函数。

 Q_OBJECT

        在Qt中,如果一个类要使用信号和槽的功能,就必须在其中声明Q_OBJECT,类的定义的第一行就写上了 Q_OBJECT。不管是不是使用信号和槽,都应该添加 O_OBJECT宏,这个宏为类提供了信号和槽机制、国际化机制以及Qt提供的不基于 C++ RTTI的反射能力。其他很多操作都会依赖于这个宏,即使类中不需要使用信号和槽,也需要添加这个宏,否则会出现编译错误。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/596586.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

我做的小程序,一下流量就爆了【小游戏:你对颜色敏感吗】

大家好&#xff0c;我是鬼哥&#xff0c;一位8年前端从业者&#xff0c;也是一位全栈开发&独立开发者&#xff0c; 最近有点浮躁&#xff0c;可笑的是2024年已经过去一个季度了&#xff0c;我今年的目标貌似都还没正式开始。 本来去年下半年计划今年开始&#xff0c;正式运…

2024.4.1-[作业记录]-day06-认识 CSS(三大特性、引入方式)

个人主页&#xff1a;学习前端的小z 个人专栏&#xff1a;HTML5和CSS3悦读 本专栏旨在分享记录每日学习的前端知识和学习笔记的归纳总结&#xff0c;欢迎大家在评论区交流讨论&#xff01; day06-认识 CSS(三大特性、引入方式) 文章目录 day06-认识 CSS(三大特性、引入方式)作业…

Apache Log4j2 Jndi RCE CVE-2021-44228漏洞原理讲解

Apache Log4j2 Jndi RCE CVE-2021-44228漏洞原理讲解 一、什么是Log4j2二、环境搭建三、简单使用Log4j2四、JDNI和RMI4.1、启动一个RMI服务端4.2、启动一个RMI客户端4.3、ldap 五、漏洞复现六、Python批量检测 参考视频&#xff1a;https://www.bilibili.com/video/BV1mZ4y1D7K…

01.IDEA中出现Cannot resolve symbol ‘SpringApplication异常

试了很多次&#xff0c;看了这篇文章终于发现了问题。IDEA解决springboot工程中Cannot resolve symbol SpringApplication异常-CSDN博客 我存在的问题在于Maven home path有误&#xff0c;改正之后就没有问题&#xff0c;不标红了。

三子棋游戏----C语言版【超级详细 + 视频演示 + 完整源码】

㊙️小明博客主页&#xff1a;➡️ 敲键盘的小明 ㊙️ ✅关注小明了解更多知识☝️ 文章目录 前言一、三子棋的实现思路二、三子棋的实现步骤2.1 先显示游戏的菜单2.2 游戏的具体实现2.2.1 棋盘的初始化2.2.2 展示棋盘2.2.3 下棋&#x1f534;玩家下棋&#x1f534;电脑下棋2.2…

【Linux】UDP编程【下】{三版本服务器/编程常见问题}

文章目录 3.linux网络涉及到的协议栈4.三个版本的服务器4.1响应式4.2命令式4.3交互式1.启动程序2.运行结果 3.linux网络涉及到的协议栈 Linux网络协议栈是一个复杂而强大的系统&#xff0c;它负责处理网络通信的各种细节。下面是对Linux网络协议栈的详细介绍&#xff1a; 套接…

小米汽车su7全色系展示源码

源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 安装教程 纯HTML&#xff0c;直接将压缩包上传网站目录解压即可 首页截图 源码下载 小米汽车su7全色系展示源码-小8源码屋源码简介 小米汽车全色系展示源码&#xff0c;小米汽车su7全色系展示源码 …

开源 _ 新一代Android 性能监控框架Rabbit

最终扫描结果会展示如下: 点击右上角导出按钮可以把扫描结果以json的形式导出到SD卡中。 网络日志监控 rabbit可以记录网络请求日志并方便的查看返回的json数据: 卡顿日志监控 rabbit通过Choreographer来检测主线程的运行情况,并异步采集主线程堆栈来还原卡顿现场。 对于下…

Qt QML的插件(Qt Quick 2 Extension Plugin)方法

Qt Quick的插件方法 序言环境前置注意概念——Qt Quick插件的相关知识模块名的相关知识模块名本身注意事项模块名版本注意事项 以示例来说明创建插件qmltypes的生成qmltypes的可能性失效 插件的编码注意1、插件模块版本控制2、pro里的注意 调用插件插件信息输入 序言 网上有很…

PostgrerSQL基本使用与数据备份

前言 上篇了解了 PostgrerSQL 数据库的部署PostgreSQL关系型数据库介绍与部署-CSDN博客&#xff0c;本篇将继续就其基本操作、备份与还原内容做相关介绍。 目录 一、数据库的操作 1. 本机登录 2. 开启远程登录 2.1 开放远程端口 2.2 编辑配置文件 2.3 修改配置密码 2.…

【opencv】示例-aruco_dict_utils.cpp 计算 ArUco 字典度量

该程序可用于计算 ArUco 字典度量。 要计算考虑翻转标记的指标&#xff0c;请使用 -r 标志。 该程序可用于创建和编写自定义 ArUco 词典。 #include <opencv2/objdetect/aruco_detector.hpp> // 包含aruco marker检测相关功能的头文件 #include <iostream> // 包含…

漂亮国的无人餐厅的机器人骚操作

导语 大家好&#xff0c;我是智能仓储物流技术研习社的社长&#xff0c;你的老朋友&#xff0c;老K。行业群 新书《智能物流系统构成与技术实践》 知名企业 读者福利&#xff1a; &#x1f449;抄底-仓储机器人-即买即用-免调试 智能制造-话题精读 1、西门子、ABB、汇川&#x…