Qt信号与槽原理

article/2025/10/1 1:24:29

Qt信号与槽原理

本文为原创文章,转载请注明出处,或注明转载自“黄邦勇帅(原名:黄勇)

本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址:
https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q
《C++语法详解》网盘地址:https://pan.baidu.com/s/1dIxLMN5b91zpJN2sZv1MNg

若对C++语法不熟悉,建议参阅本人所著《C++语法详解》一书,电子工业出版社出版,该书语法示例短小精悍,对查阅C++知识点相当方便,并对语法原理进行了透彻、深入详细的讲解,可确保读者彻底弄懂C++的原理,彻底解惑C++,使其知其然更知其所以然。此书是一本全面了解C++不可多得的案头必备图书。

信号和槽是用于对象之间的通信的,这是Qt的核心。为此Qt引入了一些关键字,他们是slots、signals、emit,这些都不是C++关键字,是Qt特有的,这些关键字会被Qt的moc转换为标准的C++语句。Qt的部件类中有一些已经定义好了的信号和槽,通常的作法是子类化部件类,然后添加自已的信号和槽。
因为信号和槽与函数相似,所以通常把信号称为信号函数,槽称为槽函数。

2.4.1 信号和槽原理

C++虽然是面象对象的语言,但程序的具体实现代码仍然是由函数来实现的,因此所谓的对象之间的通信,从程序设计语言语法角度来看就是函数调用的问题,只不过是某个对象的成员函数调用另一个对象的成员函数而已,本文从语法角度讲解信号和槽的原理,这样更容易理解信号和槽的实现原理。注:信号和槽其实是观察者模式的一种实现,有兴趣的读者可以参阅《设计模式》课程。
函数调用的几种形式
在这里插入图片描述
见图2-1,假设函数f需要g的处理结果,有以下几种处理方式
① 最简单的方式就是直接调用函数g,但这种方式有一个明显的缺点,必须知道函数g的名称“g”以及函数g的参数类型。但是若f只需要g的处理结果就可以了,而g的处理结果不一定需要函数g来完成,它也可以是x、y或其他函数来完成,那么这种直接调用函数的方式就无法胜任了,因为系统不知道用户会使用哪个函数来完成这种处理结果,也就是系统不知道调用的函数名究竟是g、x或其他名称。
② 另一种方式就是回调函数,即在函数f中使用一个指向函数的指针去调用需要的函数,这样就可以调用任意名称的函数(只要函数类型与指针相同即可),此时只要是完成了函数g功能的函数都可以作为函数f的结果被调用,这样就不会被函数名称所限制。比如
在这里插入图片描述
③ Qt使用的信号和槽机制
注意:信号和槽不是C++标准代码,因此这些代码需要使用Qt的moc进行重新编译。 其基本思想如下:
 创建一个信号,其中创建信号需要一些规则。
 当需要调用外部函数时,发送一个信号,
 此时与该信号相关联的槽便会被调用,槽其实就是一个函数,当然要使函数成为槽是有一定规则的。槽与信号的关联需要由程序员来完成。
 在Qt中,信号和槽都需要位于类之中。
 示例(具体实现时Qt引入了一些新的关键字):
在这里插入图片描述

2.4.2 创建信号和槽

只有QObject及其派生类才能使用信号和槽机制,且在类之中还需要使用Q_OBJECT宏。
1、信号需符合以下规则
 信号使用signals关键字声明,在其后面有一个冒号“:”,在其前面不能有public、private、protected访问控制符,信号默认是public的。
 信号只需像函数那样声明即可,其中可以有参数,参数的主要作用是用于和槽的通信,这就像普通函数的参数传递规则一样。信号虽然像函数,但是对他的调用方式不一样,信号需要使用emit关键字发送。
 信号只需声明,不能对其进行定义,信号是由moc自动生成的。
 信号的返回值只能是void类型的。
2、声明槽需符合以下规则
 声明槽需要使用slots关键字,在其后面有一个冒号“:”,且槽需使用public、private、protected访问控制符之一。
 槽就是一个普通的函数,可以像使用普通函数一样进行使用,槽与普通函数的主要区别是,槽可以与信号关联。
3、发射信号需符合以下规则:
 发射信号需要使用emit关键字,注意,在emit后面不需要冒号。
 emit发射的信号使用的语法与调用普通函数相同,比如有一个信号为void f(int),则发送的语法为:emit f(3);
 当信号被发射时,与其相关联的槽函数会被调用(注意:信号和槽需要使用QObject::connect函数进行关联之后,发射信号后才会调用相关联的槽函数)。
 注意:因为信号位于类之中,因此发射信号的位置需要位于该类的成员函数中或该类能见到信号的标识符的位置。
4、信号和槽的关系
 槽的参数的类型需要与信号参数的类型相对应,
 槽的参数不能多余信号的参数,因为若槽的参数更多,则多余的参数不能接收到信号传递过来的值,若在槽中使用了这些多余的无值的参数,就会产生错误。
 若信号的参数多余槽的参数,则多余的参数将被忽略。
 一个信号可以与多个槽关联,多个信号也可以与同一个槽关联,信号也可以关联到另一个信号上。
 若一个信号关联到多个槽时,则发射信号时,槽函数按照关联的顺序依次执行。
 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号。
因Qt在其类库中预定义了很多信号和槽,因此在Qt中可以仅使用Qt类库中预定义的信号和槽,也可以只使用Qt类库中预定义的信号而使用自已的槽,也可以使用Qt类库中预定义的槽来响应自已定义的信号,当然,槽和信号也都可以使用自定义的。

示例2.10:创建信号和槽
//头文件m.h的内容#ifndef M_H   
#define M_H
#include<QObject>
#include <iostream>
using namespace std;class A:public QObject{   //信号和槽必须继承自QObject类
Q_OBJECT             //必须添加该宏
//public signals:void s1(int);  //错误signals前不能有访问控制符。signals:void s();          //使用signals关键字声明信号,信号的语法与声明函数相同。signals:void s(int,int);   //正确,信号可以有参数,也可以重载。//void s2(){}          //错误,信号只需声明,不能定义。void s3();           //注意:这仍是声明的一个信号
public:                //信号声明结束后,重新使用访问控制符,表示以下声明的是成员函数。void g(){
emit s3();   /*发射信号,其语法与调用普通函数相同,在信号与槽关联之前,发射的信号不会调用相应的槽函数。*/
// emit: s3();  //错误,emit后不能有冒号。}};class B:public QObject{   Q_OBJECT
public slots:                 //使用slots关键字声明槽
void x(){cout<<"X"<<endl;}  /*正确,槽就是一个普通函数,只是需要使用slots关键字,且能和信号相关联。*///slots: void x(){}   //错误,声明槽时需要指定访问控制符。public:void g(){ // emit s3();  //错误,在类B中对于标识符s3是不可见的}	};
#endif // M_H//源文件m.cpp的内容#include "m.h"
int main(int argc, char *argv[]){    A ma;    B mb;QObject::connect(&ma,&A::s3,&mb,&B::x);  //关联信号和槽,详见后文ma.g();   //调用对象mb的成员函数x输出X,可见对象ma和mb之间实现了通信。return 0;	}

2.4.3 信号和槽的关联(连接)

信号和槽使用QObject类中的成员函数connect进行关联,该函数有多个重载版本,如下所示。
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

6、形式3与形式1的区别

① 形式1的SINGAL和SLOT宏实际是把该宏的参数转换为字符串,当信号和槽相关联时,使用的是字符串进行匹配,因此,信号和槽的参数类型的名字必须在字符串意义上相同,所以信号和槽无法使用兼容类型的参数,也因此也不能使用typedef或namespace的类型,虽然他们的实际类型相同,但由于字符串名字不同,从而无法使用形式1。
② 形式3的信号和槽函数的参数类型不需完全一致,可以进行隐式转换。形式3还支持typedef和命名空间。
③ 形式3以指针的形式指定信号和槽函数,不需再使用SIGNAL()和SLOT宏。
④ 形式3的槽函数可以不使用slots关键字声明,任意的成员函数都可以是槽函数。形式1的槽函数必须使用slots修饰。
⑤ 形式1的槽函数不受private的限制,也就是说即使槽是private的,仍可通过信号调用该槽函数,而形式3则在使用connect时就会发生错误。
⑥ 当信号或槽函数有重载的形式时,使用形式3可能会产生二义性错误,此时可使用函数指针的形式指定信号或槽函数,或者使用形式1,比如
在这里插入图片描述

示例2.11:信号和槽的关联//头文件m.h的内容
#ifndef M_H
#define M_H
#include<QObject>
#include <iostream>
using namespace std;class A:public QObject{		 Q_OBJECTsignals:void s();    void s(int,int);    void s1();    void s2(int);	 };
class B:public QObject{   Q_OBJECT
public slots:void x(){cout<<"x"<<endl;}         	void y(int i,int j){cout<<"y="<<i<<j<<endl;}void z(int){cout<<"zi"<<endl;}      void z1(float){cout<<"z1f"<<endl;}public:void z2(){   //注意,该函数未使用slots声明。cout<<"z2"<<endl; }
private slots:            //私有槽
void z3(){     cout<<"z3"<<endl;        }	};
#endif // M_H//源文件m.cpp的内容#include "m.h"
int main(int argc, char *argv[]){    A ma;    B mb;QObject::connect(&ma,SIGNAL(s()),&mb,SLOT(x()));  //形式1emit ma.s();    //输出xQObject::connect(&ma,&A::s1,&mb,&B::x);  //形式3emit ma.s1();   //输出x// QObject::connect(&ma,&A::s1,&mb,&B::y);  //错误,槽参数的数量多余信号参数的数量
//类型转换//关联失败,形式1不支持类型转换//QObject::connect(&ma,SIGNAL(s2(int)),&mb,SLOT(z1(float)));  typedef int T;//关联失败,对于形式1,类型T和int在字符串形式上并不相同。
//QObject::connect(&ma,SIGNAL(s2(T)),&mb,SLOT(z(int))); 
QObject::connect(&ma,&A::s2,&mb,&B::z1);  //正确,形式3支持隐式类型转换emit ma.s2(2);  //输出z1f
//槽函数与slots
//关联失败,形式1的槽必须使用slots声明。
//QObject::connect(&ma,SIGNAL(s1()),&mb,SLOT(z2()));QObject::connect(&ma,&A::s1,&mb,&B::z2);  //正确,形式3的槽不需使用slots声明。emit ma.s1();    /*输出x,z2,注意:在之前s1和x的关联并未断开,此时信号s1同时与槽x和z2关联。*/
//访问控制符QObject::connect(&ma,SIGNAL(s1()),&mb,SLOT(z3())); //正确,形式1的槽不受访问控制符限制。emit ma.s1();  //输出x,z2,z3,因为此时s1与多个槽相关联。//QObject::connect(&ma,&A::s1,&mb,&B::z3);//错误,z3是私有的,形式3会受访问控制符的限制。
//函数重载,形式2和形式4的使用见正文return 0;		}

作者:黄邦勇帅(原名:黄勇)

在这里插入图片描述


http://chatgpt.dhexx.cn/article/0XXsmcWx.shtml

相关文章

Qt 之 信号槽机制及优缺点

1. Qt 信号槽机制 概念&#xff1a; 信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽&#xff0c;实际就是观察者模式。当某个事件发生之后&#xff0c;比如&#xff0c;按钮检测到自己被点击了一下&#xff0c;它就会发出一个信号&#xff08;signal&#xff09;。这种发出是…

【Qt】一篇全面的信号和槽函数机制总结

信号和槽函数机制 文章目录 信号和槽函数机制一、信号和槽机制简介二、【信号】&#xff08;2-1&#xff09;信号的发出&#xff08;2-2&#xff09;信号的处理 三、【槽函数】&#xff08;3-1&#xff09;带有默认参数的信号和槽函数&#xff08;3-2&#xff09;使用QObject::…

Qt: 信号与槽机制

一、信号和槽机制是什么&#xff1f; 1 Qt信号槽机制&#xff1a;是Qt的核心机制&#xff0c;它是Qt定义的一种对象间的通讯机制&#xff0c;且独立于标准C/C语言。 2 信号&#xff08;signals&#xff09;:当某个类对象发生内部改变时&#xff0c;发射“信号”随后与关联的“槽…

Qt 信号和槽的机制(逻辑清晰的来说清楚信号和槽,呕心沥血之作)

Qt 信号和槽的机制 首先说声对不起&#xff0c;上次在PyQt5中写信号与槽&#xff0c;由于时间原因没有写完。有小伙伴留言说&#xff0c;希望把这章补全。所以&#xff0c;这是一篇迟来的文章&#xff0c;再次向大家说声抱歉。 一、桌面程序的结构 Qt的使用场景&#xff0c;…

Qt信号和槽机制emit的使用

1.相关概念&#xff1a; [1].信号&#xff08;Signal&#xff09;就是在特定情况下被发射的事件 [2].槽&#xff08;Slot&#xff09;就是对信号响应的函数。槽就是一个函数 [3].信号与槽之间的关联&#xff1a;是用 QObject::connect() 函数实现的&#xff0c;其基本格式是…

Qt信号和槽机制详解

Qt信号和槽机制详解 信号和槽是 Qt 特有的消息传输机制&#xff0c;它能将相互独立的控件关联起来。 举个简单的例子&#xff0c;按钮和窗口本是两个独立的控件&#xff0c;点击按钮并不会对窗口造成任何影响。通过信号和槽机制&#xff0c;我们可以将按钮和窗口关联起来&…

Qt信号与槽机制

一. 简介 就我个人来理解&#xff0c;信号槽机制与Windows下消息机制类似&#xff0c;消息机制是基于回调函数&#xff0c;Qt中用信号与槽来代替函数指针&#xff0c;使程序更安全简洁。 信号和槽机制是 Qt 的核心机制&#xff0c;可以让编程人员将互不相关的对象绑定在一起&…

Qt --- 信号与槽

信号与槽概述 信号与槽是 Qt 框架引以为豪的机制之一。所谓信号与槽&#xff0c;实际就是观察者模式(发布-订阅模式)。当某个事件发生之后&#xff0c;比如&#xff0c;按钮检测到自己被点击了一下&#xff0c;它就会发出一个信号&#xff08;signal&#xff09;。这种发出是没…

Qt中的信号和槽详解

一、背景介绍 信号和槽用于两个对象之间的通信。信号和槽机制是Qt的核心特征&#xff0c;也是Qt不同于其他开发框架的最突出特征。在GUI编程中&#xff0c;当改变了一个部件时&#xff0c;总希望其他部件也能了解到该变化。更一般来说&#xff0c;我们希望任何对象都可以和其他…

QT笔记(一)

学习目标&#xff1a; 总结学习的QT 学习内容&#xff1a; 1、 QT的一些固定格式 2、 控件和事件 3、 信号和槽 记录内容&#xff1a; 1、 QT的固定格式 (1) 引用头文件 自己创建的头文件用" "括起&#xff0c;eg: #include "mainwindow.h"QT提供的头文…

QT中信号和槽详解

一、QT中信号和槽的机制 1、贴图来理解信号和槽的关系 2、解释 &#xff08;1&#xff09;信号和槽是用于QT对象之间的通信&#xff0c;信号可以有某种动作触发&#xff0c;也可以直接由代码触发。 &#xff08;2&#xff09;槽也叫操函数&#xff0c;当完成了信号和槽的连接…

Qt核心特性之 —— 「信号(Signal)与槽(Slot)」机制

目录 1、Qt 与 Qt Creator简介&#xff1a; 2、关于引用头文件的一些事儿&#xff1a; 3、信号(Signal)与槽(Slot)机制&#xff1a; 3.1、一个小例子&#xff1a; 4、自定义信号与槽&#xff1a; 4.1、运行效果&#xff1a; 5、信号与槽的特性&#xff1a; 6、Qt 4…

三张图搞定TCP 握手、HTTPS、TLS加密过程

1. 抓包内容&#xff08;WireShark&#xff09; 2. 搞定握手、挥手、SSL加密过程 3. 消息内容&#xff08;Charles&#xff09; 之前看到写的比较好的文章&#xff0c;有文字详细叙述&#xff1a; TLS版本差异 https://zhuanlan.zhihu.com/p/27524995?utm_source协议解析 htt…

TCP三次握手学习心得

客户端A若要连接服务端B&#xff0c;首先A会向B发送一个连接请求&#xff0c;其中SYN1&#xff0c;ACK0&#xff0c;B为了告诉A成功收到了消息&#xff0c;则向A发送一个确认包&#xff0c;其中SYN1,ACK1,这时A收到之后又会向B发送一个确认收到确认包的确认包&#xff0c;SYN0,…

使用wireshark抓取Tcp三次握手

文章目录 wireshark的下载安装TCP协议段格式简单介绍确认应答机制介绍使用wireshark抓取TCP的三次握手 wireshark的下载安装 软件的下载可以直接去官网下载 wireshark&#xff0c;选择自己电脑适合的版本就行。 但是不咋推荐&#xff0c;原因是国外网站访问速度太慢&#xff…

TCP的三次握手、四次挥手

一、TCP的三次握手 第一次握手&#xff1a;你能和我建立连接吗&#xff0c;可以接受到我的数据吗。 SYN 1 &#xff0c;seq x 第二次握手&#xff1a;可以建立连接&#xff0c;我接受到你的请求了&#xff0c;能接受到我的数据吗&#xff0c;你的数据是这个吗 SYN 1 &#…

TCP三次握手原理

在众多的网络协议中&#xff0c;TCP协议占据着举足轻重的地位&#xff0c;你知道什么是TCP协议吗&#xff1f; 一、TCP协议 TCP(Transmission Control Protoco)协议属于计算机网络体系中的运输层。运输层的任务是负责向主机中应用层进程之间的通信提供通用的数据传输服务。所以…

TCP三次握手及四次挥手过程中的异常处理

1. 消息丢失的情况&#xff1a; 总的原则&#xff1a; ACK不会重传&#xff0c;SYN和FIN报文段有最大重传次数。无论是SYN还是FIN&#xff0c;达到最大重传次数后对端若仍无响应则直接进入CLOSED状态。 1.1 三次握手过程的消息丢失&#xff1a; 正常的三次握手的流程&#x…

HTTPS 中 TLS 和 TCP 能同时握手吗?

HTTPS 中 TLS 和 TCP 能同时握手吗&#xff1f; 大家好&#xff0c;我是小林。 有位读者在面试的时候&#xff0c;碰到这么个问题&#xff1a; 面试官跟他说 HTTPS 中的 TLS 握手过程可以同时进行三次握手&#xff0c;然后读者之前看我的文章是说「先进行 TCP 三次握手&#…

TCP优化一:TCP 三次握手的优化

TCP 三次握手的性能提升 TCP 是面向连接的、可靠的、双向传输的传输层通信协议&#xff0c;所以在传输数据之前需要经过三次握手才能建立连接。 那么&#xff0c;三次握手的过程在一个 HTTP 请求的平均时间占比 10% 以上&#xff0c;在网络状态不佳、高并发或者遭遇 SYN 攻击…