Qt的信号与槽

article/2025/10/1 13:13:56

引入

在GUI编程中,组件组件如何实现通信是核心的技术内容。
Qt使用了信号与槽的机制,为此Qt引入了一些关键字slots、signals、emit,这些都是Qt特有的关键字,然后这些关键字会被Qt的moc转换位标准的C++语句。

Qt 的部件类中有一些已经定义好了的信号和槽,通常的作法是子类化部件类,然后添加自已的信号和槽。

因为信号和槽与函数相似,所以通常把信号称为信号函数,槽称为槽函数。

元对象是指用于描述另一个对象结构的对象。使用编程语言具体实现时,其实就是一个类的对象,只不过这个对象专门用于描述另一个对象而已,比如 class B{…}; class A{…B mb;…};假设 mb 是用来描述类 A 创建的对象的,则 mb 就是元对象

什么是信号和槽?(signal and slot)

C++虽然是面象对象的语言,但程序的具体实现代码仍然是由函数来实现的,因此所谓的对象之间的通信,从程序设计语言语法角度来看就是函数调用的问题,只不过是某个对象的成员函数调用另一个对象的成员函数而已。信号和槽其实是观察者模式的一种实现。

当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。

我们打开Qt ui设计师,在里面放一个组件,右键点击它就可以转到槽了:

在这里插入图片描述

转到槽qt会提供很多信号函数给你用,一个信号函数代表了一个事件,当事件发生的时候就会调用相应的信号函数;
例如clicked():当这个按钮被点击的时候触发的信号函数
在这里插入图片描述

选好信号函数之后,Qt会很贴心的帮你命好槽函数的名字,并帮你绑定对应的信号函数
在这里插入图片描述

你也可以显示的把信号函数和槽函数的绑定写出来,或者你想自己绑定其他的信号或者槽函数:
通过连接函数实现
连接函数 :connect(参数1,参数2,参数3,参数4)

  • 参数1 信号的发送者
  • 参数2 发送的信号(函数地址)
  • 参数3 信号的接受者
  • 参数4 处理的槽函数 (函数的地址)
//实现点击按钮 关闭窗口的案例
connect(btn , &QPushButton::click,this,&QWidget::close );

我们直接看代码,我们不仅仅实现一个自动添加的槽函数,我们还自己写一个槽函数和信号函数供大家深入理解它的含义

Mainwindow.h

#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
namespace Ui {
class MainWindow;
}
class MainWindow : public QMainWindow
{Q_OBJECT// 只有 QObject 及其派生类才能使用信号和槽机制,且在类之中还需要使用 Q_OBJECT 宏。
public:explicit MainWindow(QWidget *parent = 0);~MainWindow();
private:Ui::MainWindow *ui;
signals:    //信号void print(QString str); //自己添加的信号函数
private slots:    //槽函数void on_pushButton_clicked();//qt帮你生成的槽函数void printString(QString str);//自己定义的槽函数
};
#endif // MAINWINDOW_H

mainwindow.cpp

#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :QMainWindow(parent),ui(new Ui::MainWindow)
{ui->setupUi(this);connect(this,&MainWindow::print,this,&MainWindow::printString);
}
void MainWindow::onClicked()
{if(ui->pushButton->text() == "Hello,World"){ui->pushButton->setText("一个普通的按钮");}else{ui->pushButton->setText("Hello,World");emit this->print("Hello,World");//向print这个信号函数发一个信号,//由于print信号函数和printString直接关联,//print信号函数再向printString这个槽函数发信号}
}
void MainWindow::printString(QString str)
{qDebug()<<"要打印的字符串是:"<<str;
}
MainWindow::~MainWindow()
{delete ui;
}

信号与槽的原理

创建一个信号,其中创建信号需要一些规则。当需要调用外部函数时,发送一个信号,此时与该信号相关联的槽便会被调用,槽其实就是一个函数,当然要使函数成为槽是有一定规则的。

只有 QObject 及其派生类才能使用信号和槽机制,且在类之中还需要使用 Q_OBJECT 宏。

槽与信号的关联需要由程序员来完成

在 Qt 中,信号和槽都需要位于一个类之中。

几个关键字的原型:

  • signals 关键字:最终被#define 置换为一个访问控制符,其简化后为 #define signals public

  • slots 关键字:最终被#define 置换为一个空宏,即简化后为 #define slots

  • emit 关键字:同样被#define 置换为一个空宏,即简化后为 #define emit

由以上各关键字原型可见,使用 emit 发射信号,其实就是一个简单的函数调用。

signals信号创建规则:

  • 信号使用 signals 关键字声明,在其后面有一个冒号“:”,在其前面不能有 public、private、protected 访问控制符,信号默认是 public 的(因为事件的本质其实是Windows的一个类发出来的一个消息,例如点击事件是Windows的鼠标类来处理的,这个消息最后再发送给Qt的应用程序类的信号函数,所以要公开访问权限)

  • 信号只需像函数那样声明即可,其中可以有参数,参数的主要作用是用于和槽的通信,这就像普通函数的参数传递规则一样。信号虽然像函数,但是对他的调用方式不一样,信号需要使用 emit 关键字发射。

  • 信号只需声明,不能对其进行定义,信号是由 moc 自动生成的。

  • 信号的返回值只能是 void 类型的。

槽创建规则:

  • 声明槽需要使用 slots 关键字,在其后面有一个冒号“:”,且槽需使用 public、private、protected 访问控制符之一。(如果没有外部访问的必要建议设置位private,默认转到槽的生成就是私有的)

  • 槽就是一个普通的函数,可以像使用普通函数一样进行使用,槽与普通函数的主要区别是,槽可以与信号关联

发射信号规则:

  • 发射信号需要使用 emit 关键字,注意,在 emit 后面不需要冒号。

  • emit 发射的信号使用的语法与调用普通函数相同,比如有一个信号为 void f(int),则发送的语法为:emit f(3);

  • 当信号被发射时,与其相关联的槽函数会被调用(注意:信号和槽需要使用QObject::connect 函数进行关联之后,发射信号后才会调用相关联的槽函数)

  • 因为信号位于类之中,因此发射信号的位置需要位于该类的成员函数中或该类能见到信号的标识符的位置。

信号和槽的关系

  • 槽的参数的类型需要与信号参数的类型相对应,

  • 槽的参数不能多于信号的参数,因为若槽的参数更多,则多余的参数不能接收到信号传递过来的值,若在槽中使用了这些多余的无值的参数,就会产生错误。

  • 若信号的参数多余槽的参数,则多余的参数将被忽略。

  • 一个信号可以与多个槽关联,多个信号也可以与同一个槽关联,信号也可以关联到另一个信号上

  • 若一个信号关联到多个槽时,则发射信号时,槽函数按照关联的顺序依次执行。

  • 若信号连接到另一个信号,则当第一个信号发射时,会立即发射第二个信号

信号和槽的绑定机制

除了像我上面写的那样将connect绑定函数写到类的构造函数中之外,还有其他的使用方式。
我们先简单介绍一下这个connect函数,从声明上来看就能知道它可以怎么用。

connect函数的具体声明如下:

static QMetaObject::Connection connect(const QObject *sender,   const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection) const
  • sender:表示需要发射信号的对象。

  • signal:表示需要发射的信号,该参数必须使用 SIGNAL()宏。

  • receiver:表示接收信号的对象。

  • method:表示与信号相关联的槽函数,这个参数也可以是信号,从而实现信号与信号的关联。该参数若是槽,需使用 SLOT()宏,若是信号需使用 SIGNAL() 宏。

  • 返回值的类型为 QMetaObject::Connection,如果成功将信号连接到槽,则返回连接的句柄,否则,连接句柄无效,可通过将句柄转换为 bool 来检查该句柄是否有效。该返回值可用于 QObject::disconnect()函数的参数,以断开该信号和槽的关联。

  • type:用于指明信号和槽的关联方式,它决定了信号是立即传送到一个槽还是在稍后时间排队等待传送。关联方式使用枚举 Qt::ConnectionType 进行描述,下表为其取值及意义:

常量描述
Qt::AutoConnection(自动关联,可以缺省,默认值)。若接收者驻留在发射信号的线程中(即信号和槽在同一线程中),则使用 Qt :: DirectConnection(直接关联),否则,使用 Qt :: QueuedConnection(队列关联)。当信号发射时自动确定使用哪种关联类型。
Qt::DirectConnection直接关联。当信号发射后,立即调用槽。在槽执行完之后,才会执行发射信号之后的代码(即 emit 关键字之后的代码)。该槽在信号线程中执行。
Qt::QueuedConnection队列关联。当控制权返回到接收者线程的事件循环后,槽才会被调用,也就是说 emit 关键字后面的代码将立即执行,槽将在稍后执行,该槽在接收者的线程中执行。
Qt::BlockingQueuedConnection阻塞队列关联。和 Qt :: QueuedConnection 一样,只是信号线程会一直阻塞,直到槽返回。如果接收者驻留在信号线程中,则不能使用此连接,否则应用程序将会死锁。
Qt::UniqueConnection唯一关联。这是一个标志,可使用按位或与上述任何连接类型组合。当设置 Qt :: UniqueConnection 时,则只有在不重复的情况下才会进行连接,如果已经存在重复连接(即,相同的信号指向同一对象上的完全相同的槽),则连接将失败,此时将返回无效的 QMetaObject::Connection

从声明中能看出来,它是QObject的static函数,所以可以直接在外部类声明使用

方式1(直接声明使用)


class A:public QObject {Q_OBJECT 
singals: void s(int i);
};
class B:public QObject{Q_OBJECT 
public slots: void x(int i){}
};
A ma; B mb; 
QObject::connect (&ma, SIGNAL(s(int)), &mb, SLOT(x(int));
  • 这种方式是将绑定函数写成全局函数引用的方式,connect是QObject的一个static函数,所以可以这么用;
  • 使用的时候,信号的指定须使用宏SIGNAL(),槽须使用宏SLOT(),这两个能把括号中的内容转换为与形参相对应的const char*形式。
  • 在指定函数时,只能指定函数参数的类型,不能有参数名,也不能指定函数的返回类型。

方式2(Object调用使用)

 A ma; B mb; mb.connect(&ma, SIGNAL(s(int)),SLOT(x(int));

这种方式就是传统的调用方式

方式3(参数上可以使用模板)

 A ma; B mb; QObject::connect(&ma, &A::s, &mb, &B::x );

该函数对信号和槽函数的指定方式不是使用的宏。该形式的函数其实是一个模板函数,通过以指针的形式来指定信号和槽函数来达到不再使用SIGNAL()和SLOT()宏的目的
使用这种方式也有很多其他的好处:

  • 这种方式的槽函数可以不使用slots关键字声明,任意的成员函数都可以是槽函数

  • 这种方式的信号和槽函数的参数类型不需要完全一致,可以进行隐式转换,甚至可以用typedef和命名空间( SINGAL()和SLOT()宏实际上是把该宏的参数转换为字符串,当信号和槽相关联的时候,使用的是字符串进行匹配,所以信号和槽的参数类型必须在字符串意义上相同,所以使用宏的方式无法兼容类型的参数)

  • 当信号或槽函数有重载时,使用这种方式可能会产生二义性的问题,我们可以使用函数指针的方法指定信号或槽函数

class A:public QObject {Q_OBJECT 
singals:void s(int i);
};
class B:public QObject{Q_OBJECT
public slots:void x(){} void x(int i){}//槽函数重载
};
A ma; B mb; 
//QObject::connect(&ma, &A::s, &mb, &B::x ); //会发生二义性错误。
//可使用如下方式解决(对于信号类似)
QObject::connect(&ma, &A::s, &mb,static_cast<void (B::*)(int)> (&B::x));

方式4(在构造函数中使用)

这种使用方式是写在了界面窗口类的构造函数中,具体代码可以看最上面我的实现,可以简化很多写的东西(例如实例对象可以用this替换等等),如果绑定的函数过多,建议专门再写一个init初始化的函数将所有的绑定过程放到初始化函数中

断开连接的机制

可以建立信号和槽的绑定关系,就肯定可以断开其关联,我们使用disconnect函数断开其连接,使用方式和connect类似,这里不再赘述了

它的函数声明如下,断开成功返回true:

static bool QObject::disconnect( const QObject *sender, const char *signal, const QObject *receiver, const char *method)const

参考

Qt学习之Qt基础入门(上)

Qt教程(3) : 信号与槽


http://chatgpt.dhexx.cn/article/PZ8WVJN4.shtml

相关文章

Linux下的QT信号和槽机制(二)

目录 1.基本知识点 2.信号机制 3.槽机制 4.元对象工具 5.信号和槽机制原理 &#xff08;1&#xff09;信号和槽机制 &#xff08;2&#xff09;信号和槽函数的关联 &#xff08;3&#xff09;信号和槽的断开 &#xff08;4&#xff09;信号和槽的优点 &#xff08;5&…

Qt信号与槽原理

Qt信号与槽原理 本文为原创文章&#xff0c;转载请注明出处&#xff0c;或注明转载自“黄邦勇帅(原名&#xff1a;黄勇) 本文出自本人原创著作《Qt5.10 GUI完全参考手册》网盘地址&#xff1a; https://pan.baidu.com/s/1iqagt4SEC8PUYx6t3ku39Q 《C语法详解》网盘地址&#…

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…