【Qt】—— 信号与槽

简介: 【Qt】—— 信号与槽



(一)信号和槽概述

在Qt中,每次用户与控件互动的过程都被称为一个事件。举例来说,"用户点击按钮"是一个事件,"用户关闭窗口"也是一个事件。每个事件都会触发相应的信号,例如,当用户点击按钮时,会发出"按钮被点击"的信号;当用户关闭窗口时,会发出"窗口被关闭"的信号。这种事件和信号的机制使得在Qt应用程序中能够方便地处理用户交互和相应的行为。

在Qt中,每个控件都具备接收信号的能力,并且一个控件可以同时接收多个不同的信号。每当控件接收到信号时,它会执行相应的响应动作。举例来说,当窗口中的按钮接收到"按钮被点击"的信号时,它会执行"关闭自身"的响应动作;又如,当文本输入框接收到"文本框被点击"的信号时,它会执行"显示闪烁的光标,等待用户输入数据"的响应动作。在Qt中,对信号所做出的响应动作被称为槽函数

信号和槽是Qt独有的消息传递机制,它能够连接不同的控件并使它们相互影响。举例来说,"按钮"和"窗口"是两个独立的控件,单纯点击按钮并不会对窗口产生任何影响。通过信号和槽机制,可以将按钮和窗口连接起来,实现"点击按钮会导致窗口关闭"的效果。

1.1 信号的本质

信号是由用户对窗口或控件进行操作所触发的特定事件,这些事件会导致相应的窗口类或控件类发出特定的信号,从而对用户的操作作出响应。因此,从本质上讲,信号就是事件的一种体现

例如:

  • 按钮单击、双击
  • 窗⼝刷新
  • ⿏标移动、⿏标按下、⿏标释放
  • 键盘输⼊

那么在Qt中信号是通过什么形式呈现给使⽤者的呢?

  • 我们对哪个窗⼝进⾏操作,哪个窗⼝就可以捕捉到这些被触发的事件。
  • 对于使⽤者来说触发了⼀个事件我们就可以得到Qt框架给我们发出的某个特定信号。
  • 信号的呈现形式就是函数,也就是说某个事件产⽣了,Qt框架就会调⽤某个对应的信号函数,通知使⽤者。

在Qt中信号的发出者是某个实例化的类对象


1.2 槽的本质

(Slot)是对信号进行响应的函数。槽函数与一般的C++函数类似,可以定义在类的任何位置(public、protected或private),可以具有任意参数,可以被重载,也可以直接调用(但不能有默认参数)。

  • 与一般函数不同的是:槽函数可以与一个信号相关联。当信号被发射时,与之关联的槽函数会自动执行。

1)信号和槽机制在底层通过函数间的相互调用来实现。每个信号可以用函数表示,称为信号函数;每个槽也可以用函数表示,称为槽函数。例如,"按钮被按下"这个信号可以用clicked()函数表示,而"窗口关闭"这个槽可以用close()函数表示。因此,使用信号和槽机制实现"点击按钮会关闭窗口"的功能实质上是clicked()函数调用close()函数的效果。

2)信号函数和槽函数通常位于某个类中。相较于普通的成员函数,它们的特殊之处在于:

  • 信号函数用signals关键字修饰,槽函数用public slots、protected slots或private slots修饰。signals和slots是Qt在C++基础上扩展的关键字,专门用于指明信号函数和槽函数;
  • 信号函数只需声明,无需定义(实现),而槽函数需要定义(实现)。
  • 信号函数的定义是Qt⾃动在编译程序之前⽣成的.编写Qt应⽤程序的程序猿⽆需关注.
  • 这种⾃动⽣成代码的机制称为元编程(Meta Programming).这种操作在很多场景中都能⻅到.

(二)信号和槽的使用

2.1 信号和槽的连接

信号与槽的连接是Qt中用于建立信号与槽关联关系的重要机制。通过连接,一个信号可以触发一个或多个槽函数的执行,实现对象之间的通信。

在Qt中,QObject类(QObjectQt内置的⽗类.Qt中提供的很多类都是直接或者间接继承⾃QObject)提供了⼀个静态成员函数connect(),该函数专⻔⽤来关联指定的信号函数和槽函数。

connect()函数原型:

connect (const QObject *sender,
        const char * signal ,
        const QObject * receiver ,
        const char * method ,
        Qt::ConnectionType type = Qt::AutoConnection )

参数说明:

  • sender:信号的发送者;
  • signal:发送的信号(信号函数);
  • receiver:信号的接收者;
  • method:接收信号的槽函数;
  • type:⽤于指定关联⽅式,默认的关联⽅式为Qt::AutoConnection,通常不需要⼿动设定。

 


2.2 查看内置信号和槽

1、系统⾃带的信号和槽通常是通过"Qt帮助⽂档"来查询。

2、如上述⽰例,要查询"按钮"的信号,在帮助⽂档中输⼊:QPushButton

  • ⾸先可以在"Contents"中寻找关键字signals,
  • 如果没有找到,继续去⽗类中查找.因此我们去他的⽗类QAbstractButton中继续查找关键字signals

这⾥的clicked()就是要找的信号。槽函数的寻找⽅式和信号⼀样,只不过它的关键字是slot。

 

2.3 通过Qt Creator⽣成信号槽代码

Qt Creator可以快速帮助我们⽣成信号槽相关的代码。

代码示例:在窗⼝中设置⼀个按钮,当点击"按钮"时关闭"窗⼝".

1、新建项⽬,如下图为新建完成之后所包含的所有⽂件(创建时要⽣成UI设计⽂件)

2、双击widget.ui⽂件,进⼊UI设计界⾯;

3、在UI设计窗⼝中拖⼊⼀个"按钮",并且修改"按钮"的名称及字体大小等;

4、可视化⽣成槽函数;

  • 当单击"转到槽..."之后,出现如下界⾯:对于按钮来说,当点击时发送的信号是:clicked(),所以此处选择:clicked()

  • 对于普通按钮来说,使⽤ clicked 信号即可.clicked(bool) 没有意义的.具有特殊状态的按钮(⽐如复选按钮)才会⽤到 clicked(bool) .

5、⾃动⽣成槽函数原型框架;

(1)在"widget.h"头⽂件中⾃动添加槽函数的声明;

【解释说明】

⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中:

  • 1、以"on"开头,中间使⽤下划线连接起来;
  • 2、"XXX"表⽰的是对象名(控件的 objectName 属性)。
  • 3、"SSS"表⽰的是对应的信号。

如:"on_pushButton_clicked()",pushButton代表的是对象名,clicked是对应的信号。


(2)在"widget.cpp"中⾃动⽣成槽函数定义.


6、在槽函数函数定义中添加要实现的功能.实现关闭窗⼝的效果(即当我们运行代码点击关闭按钮之后窗口就会自动关闭)

 


(三)自定义信号和槽

 

3.1 基本语法

 

在Qt中,可以自定义信号和槽函数以满足特定需求。然而,自定义的信号函数和槽函数应该遵循一定的书写规范。

1、⾃定义信号函数书写规范

  • ⾃定义信号函数必须写到"signals"下;
  • 返回值为void,只需要声明,不需要实现;
  • 可以有参数,也可以发⽣重载;

2、⾃定义槽函数书写规范

  • 早期的Qt版本要求槽函数必须写到"publicslots"下,但是现在⾼级版本的Qt允许写到类的"public"作⽤域中或者全局下;
  • 返回值为void,需要声明,也需要实现;
  • 可以有参数,可以发⽣重载;

3、发送信号

  • 使⽤"emit"关键字发送信号。"emit"是⼀个空的宏。"emit"其实是可选的,没有什么含义,只是为了提醒开发⼈员。

⽰例1:

1、在widget.h中声明⾃定义的信号和槽,如图所⽰;

2、在widget.cpp中实现槽函数,并且关联信号和槽

注意:图中的①和②的顺序不能颠倒

原因是,⾸先关联信号和槽,⼀旦检测到信号发射之后就会⽴⻢执⾏关联的槽函数。反之,若先发射信号,此时还没有关联槽函数,当信号发射之后槽函数不会响应.


3.2 带参数的信号和槽

Qt的信号和槽也⽀持带有参数,同时也可以⽀持重载.

此处我们要求,信号函数的参数列表要和对应连接的槽函数参数列表⼀致.

此时信号触发,调⽤到槽函数的时候,信号函数中的实参就能够被传递到槽函数的形参当中.

(💡 通过这样的机制,就可以让信号给槽传递数据了.)

示例:重载信号槽

(1)在"widget.h"头⽂件中声明重载的信号函数以及重载的槽函数;如下图所⽰:

(2)在"Widget.cpp"⽂件实现重载槽函数以及连接信号和槽。

  • 需要注意的是:在定义函数指针时要指明函数指针的作⽤域。

(3)执⾏结果如下图所⽰:

 


(四)信号与槽的连接⽅式

4.1 ⼀对⼀

主要有两种形式,分别是:⼀个信号连接⼀个槽⼀个信号连接⼀个信号

(1)⼀个信号连接⼀个槽

 

代码⽰例:

1、在"widget.h"中声明信号和槽以及信号发射函数;

 

2、在"widget.cpp"中实现槽函数,信号发射函数以及连接信号和槽;

(2)⼀个信号连接另⼀个信号

代码示例:

在上述⽰例的基础上,在"widget.cpp"⽂件中添加如下代码:

 


4.2 ⼀对多

⼀个信号连接多个槽

⽰例:

(1)在"widget.h"头⽂件中声明⼀个信号和三个槽;

(2)在"widget.cpp"⽂件中实现槽函数以及连接信号和槽;

 

 


4.3 多对⼀

多个信号连接⼀个槽函数

⽰例:

(1)在"widget.h"头⽂件中声明两个信号以及⼀个槽;

(2)在"widget.cpp"⽂件中实现槽函数以及连接信号和槽;


(五)信号和槽的其他说明

5.1 信号与槽的断开

在Qt中,可以使用 disconnect 函数来断开信号与槽之间的连接。disconnect 函数允许你在运行时动态地断开连接,以便停止两个对象之间的信号和槽的关联。(disconnect的⽤法和connect基本⼀致.)

代码示例:

  • 需要注意的是,断开连接时,必须提供与建立连接时相同的参数,包括信号函数和槽函数的指针或函数指针。

5.2 Qt4版本信号与槽的连接

Qt4中的connect⽤法和Qt5相⽐是更复杂的.需要搭配 SIGNAL 和 SLOT 宏来完成。⽽且缺少必要的函数类型的检查,使代码更容易出错。

代码示例:

(1)在"widget.h"头⽂件中声明信号和槽

(2)在"widget.cpp"⽂件中实现槽函数以及连接信号与槽;

Qt4版本信号与槽连接的优缺点:

  • 优点:参数直观;
  • 缺点:参数类型不做检测;

代码示例:


5.3 使⽤Lambda表达式定义槽函数

Qt5在Qt4的基础上提⾼了信号与槽的灵活性,允许使⽤任意函数作为槽函数。

但如果想⽅便的编写槽函数,⽐如在编写函数时连函数名都不想定义,则可以通过Lambda表达式来达到这个⽬的。

在Qt中,可以使用Lambda表达式来定义槽函数,这使得代码更加简洁和可读。Lambda表达式是C++11引入的一种匿名函数形式,允许我们在需要函数的地方内联定义函数。

下面是一个使用Lambda表达式定义槽函数的示例:

// 假设有一个QPushButton对象 btn
connect(btn, &QPushButton::clicked, [=]() {
    qDebug() << "按钮被点击了";
    // 在这里写下按钮被点击时需要执行的操作
});

【解释说明】

  • 在这个示例中,我们将按钮的clicked信号与一个Lambda表达式连接起来。
  • Lambda表达式作为槽函数,使用了方括号[]来捕获外部变量,这里使用了捕获所有外部变量的方式[=]。
  • Lambda表达式中的代码将会在按钮被点击时执行。

5.4 信号与槽的优缺点

优点:松散耦合

  • 信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了⾃⼰,Qt的信号槽机制保证了信号与槽函数的调⽤。⽀持信号槽机制的类或者⽗类必须继承于QObject类。

缺点:效率较低

  • 与回调函数相⽐,信号和槽稍微慢⼀些,因为它们提供了更⾼的灵活性,尽管在实际应⽤程序中差别不⼤。
  • 通过信号调⽤的槽函数⽐直接调⽤的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调⽤速度对性能要求不是⾮常⾼的场景是可以忽略的,是可以满⾜绝⼤部分场景。

总结

在Qt中,信号与槽是一种强大的通信机制,用于在对象之间进行异步通信。以下是关于信号与槽的简要小结:

  1. 信号
  • 信号是Qt中特有的概念,是一种特殊的成员函数,用于通知其他对象发生了某种特定的事件。
  • 信号由signals:关键字声明,在类的声明部分中定义。
  • 信号函数通常不包含实际的实现,只是用来发出信号。
  • 信号函数可以有参数,参数的类型必须是Qt元对象系统支持的数据类型。
  • 槽是用于响应信号的函数,可以执行特定的操作以响应信号的发生。
  • 槽函数由slots:关键字声明,在类的声明部分中定义。
  • 槽函数可以是普通成员函数、静态成员函数或者Lambda表达式。
  • 槽函数的参数类型必须与连接的信号的参数类型匹配。
  1. 连接
  • 连接是指建立信号与槽之间的关联,使得当信号被发出时,相关的槽函数会被调用。
  • 连接通过QObject::connect()函数来实现,可以连接两个QObject对象之间的信号和槽。
  • 在连接时,需要指定发送信号的对象、信号函数、接收信号的对象以及槽函数。
  • 连接还可以使用Qt 5中引入的新语法,使得连接更加类型安全。
  1. 自定义信号与槽
  • Qt允许自定义信号和槽函数,以满足特定需求。
  • 自定义的信号函数和槽函数应该遵循一定的书写规范,例如在类的声明部分中使用signals:slots:关键字声明。
  • 自定义的信号函数和槽函数可以有参数,参数的类型必须是Qt元对象系统支持的数据类型。

使用信号与槽机制可以实现对象之间的松耦合通信,使得代码更加模块化、可维护和可扩展。

相关文章
|
6月前
10 QT - 自定义信号和槽
10 QT - 自定义信号和槽
35 0
|
7月前
|
数据可视化 容器
Qt 之 QPushButton,信号与槽机制
Qt 之 QPushButton,信号与槽机制
96 0
|
4天前
|
编译器 API
【Qt】- 信号和槽函数
【Qt】- 信号和槽函数
|
22天前
|
编译器 C++ 索引
【Qt 学习笔记】详解Qt中的信号和槽
【Qt 学习笔记】详解Qt中的信号和槽
31 0
|
3月前
|
编译器 C++ 开发者
QT基础【5-信号与槽】
QT基础【5-信号与槽】
|
4月前
|
设计模式 安全
Qt信号和槽
Qt信号和槽
27 1
|
4月前
Qt6学习笔记二(信号槽)
Qt6学习笔记二(信号槽)
38 0
|
5月前
|
算法 编译器
[C++&Qt] 通过信号与槽传递数据
[C++&Qt] 通过信号与槽传递数据
52 0
|
8月前
|
安全 C++
Qt的信号与槽机制
Qt的信号与槽机制
41 0
|
9月前
|
安全 C++ 开发者
QT信号与槽
信号槽是 Qt 框架引以为豪的机制之一。熟练使用和理解信号槽,能够设计出解耦的非常漂亮的程序,有利于增强我们的技术设计能力。
137 0

推荐镜像

更多