目录
?前言?
? 信号和槽的概念
? 使用信号和槽
? 代码关联信号槽
? Qt Creator自动生成信号槽代码
? 自定义信号和槽
? 自定义槽
? 自定义信号
? 带参数的信号和槽
? 断开信号槽的连接
? lambda表达式定义槽
? Qt信号槽的存在的意义
? 总结
?前言?
本期内容主要讲解Qt中重要概念——信号槽。信号槽是一种解决问题的方案,响应用户操作,处理问题。
本期内容主要围绕如何使用信号槽,信号槽它的优缺点有哪些进行讲解,零基础学会Qt开发中的信号槽。
? 信号和槽的概念
Qt中信号的概念与Linux中信号的概念十分类似,如果你有学习过Linux中信号的概念,那么你也就理解了Qt中信号的概念。
【Linux杂货铺】进程信号-CSDN博客
在Qt中,用户和控件的每次交互过程称为一个事件,每个事件都会发送一个信号。例如“用户点击按钮”是一个事件,会发出“按钮被点击”的信号。
每个控件都具有接受发送信号的能力,一个控件还能接受多个不同的信号。对于接收到的信号,控件会做出响应动作,做出的响应动作称为槽。
在Linux中信号是进程间通信机制,进程收到信号后回去执行回调函数。Qt中也是一样,信号和槽是Qt独有的信息传送机制,将相互独立的空间关联起来。
信号的本质就是一个事件,槽的本质就是一个回调函数。在Qt中信号的呈现形式是函数,某事件发生时,Qt会执行对应的信号函数,通知使用者,信号的发出者是某个实例化的对象。
每个信号可以用函数表示,成为信号函数;每个槽也可以用函数示,称为槽函数。
信号和槽函数通常位于某个类中,信号函数用signals关键字修饰,槽函数用public slots,protected slots或者private slots修饰(Qt5与上版本可以省略slots)。
信号函数只需要声明,不需要定义,而槽函数需要定义。
一般情况下,我们很少使用自定义信号,Qt提供的信号足够应付大部分场景,如果某种特定需要,需要自定义信号,那我们就需要在一个类中声明一个信号函数,但是不需要定义信号函数。
信号函数的定义是Qt自动在编译程序之前生成的,编写Qt应用程序的程序员无需关注。这种自动生成代码的机制称为元编程。
? 使用信号和槽
Qt中,QObject类提供了一个静态成员函数connec(),该函数专门用来关联指定的信号函数和槽函数。(QObject是Qt内置的父类,Qt提供的需要类都是直接或间接继承QObject,QObject可以理解为是一个祖宗类)
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,通常不需要手动设定。
? 代码关联信号槽
下面代码主要实现按下按钮时,窗口会被关闭。
此时clicked和close都是类中的函数,而不是char*类型,那么为什么能调用connect呢?因为上述connect是文档中的原型,但是文档并没有更新,现在connect可以支持传递函数类型。但是signal必须是sender中的成员函数,method必须是receiver中的成员函数。
我们也可以使用自定义槽,来改变窗口标题:
? Qt Creator自动生成信号槽代码
上述代码,改变窗口标题我们可以可以通过设计窗口来完成:
Qt Creator会自动生产代码,我们我们只需要在函数内完成槽的逻辑即可,不需要关联信号和槽,Qt会自动关联。
这两种方案都能够将信号和槽关联起来,具体使用哪种方式,看你自己需求。
⾃动⽣成槽函数的名称有⼀定的规则。槽函数的命名规则为:on_XXX_SSS,其中: 1、以 " on " 开头,中间使⽤下划线连接起来; 2、" XXX " 表⽰的是对象名(控件的 objectName 属性)。 3、" SSS " 表⽰的是对应的信号。 如:" on_pushButton_clicked() " ,pushButton 代表的是对象名,clicked 是对应的信号。按照这种命名⻛格定义的槽函数, 就会被 Qt ⾃动的和对应的信号进⾏连接.
? 自定义信号和槽
? 自定义槽
(1)早期的 Qt 版本要求槽函数必须写到 "public slots" 下,但是现在高级版本的 Qt 允许写到类的"public" 作用域中或者全局下;
(2)返回值为 void,需要声明,也需要实现;
(3)可以有参数,可以发送重载;
? 自定义信号
(1)自定义信号函数必须写到 "signals" 下;
(2)返回值为 void,只需要声明,不需要实现;
(3)可以有参数,也可以发生重载;
使用“emit”关键字发送信号,“emit”是一个空的宏,是可选项,没有什么含义,只是为了提醒开发人员。
? 带参数的信号和槽
Qt 的信号和槽也⽀持带有参数, 同时也可以⽀持重载。
此处我们要求, 信号函数的参数列表要和对应连接的槽函数参数列表⼀致。这里的一致是参数类型一致,个数可以不一致,当参数个数不一致时,槽函数的参数小于信号参数的参数,槽函数会按照参数顺序,拿到信号的前N个参数
通过参数传递可以达到代码复用的效果
一个槽函数可能会绑定多个信号,如果我们严格要求槽函数与某个信号函数个数一致,意味着信号绑定到槽的要求提高了。
? 信号和槽的连接方式
? 一对一
一对一又分为一个信号对应一个槽和一个信号对应一个信号。
一个信号对应一个槽:
一个信号对应一个信号:
? 一对多
⼀个信号连接多个槽:
? 多对一
多个信号连接⼀个槽函数:
? 断开信号槽的连接
使用disconnect断开连接。主动断开往往是因为信号要绑定到一个新的槽上,为了避免同时调用两个槽,而主动断开。
? lambda表达式定义槽
lambda表达式的定义式如下:
[ capture ] ( params ) opt -> ret {Function body;}
符号 | 说明 |
[ ] | 局部变量捕获列表。Lambda表达式不能访问外部函数体的任何局部变量 |
[a] | 在函数体内部使⽤值传递的⽅式访问a变量 |
[&b] | 在函数体内部使⽤引⽤传递的⽅式访问b变量 |
[=] | 函数外的所有局部变量都通过值传递的⽅式使⽤, 函数体内使⽤的是副本 |
[&] | 以引⽤的⽅式使⽤Lambda表达式外部的所有变量 |
[=, &foo] | foo使⽤引⽤⽅式, 其余是值传递的⽅式 |
[&, foo] | foo使⽤值传递⽅式,其余引⽤传递 |
[this] | 在函数内部可以使⽤类的成员函数和成员变量,= 和 & 形式也都会默认引⼊ |
由于使用引用方式捕获对象会有局部变量释放了而Lambda函数还没有被调用的情况。如果执行Lambda函数,那么引用传递方式捕获进来的局部变量的值不可预知。所以绝大多数场合使用的形式为: [=] () { }。
? Qt信号槽的存在的意义
信号和槽的优点:
1. 高内聚低耦合,信号发送者不需要知道发出的信号被哪个对象的槽函数接收,槽函数也不需要知道哪些信号关联了自己,Qt的信号槽机制保证了信号与槽函数的调用。支持信号槽机制的类或者父类必须继承于 QObject 类。
2. 可以支持多对多,即一个信号可以有多个槽,一个槽可以有多个信号。
缺点:
效率较低,与回调函数相比,信号和槽稍微慢⼀些,因为它们提供了更高的灵活性,尽管在实际应用程序中差别不大。通过信号调用的槽函数比直接调用的速度慢约10倍(这是定位信号的接收对象所需的开销;遍历所有关联;编组/解组传递的参数;多线程时,信号可能需要排队),这种调用速度对性能要求不是非常高的场景是可以忽略的,是可以满足绝大部分场景。
? 总结
以上就是本期内容,主要讲解了Qt中信号和槽的概念,如何使用信号和槽等。
如果感觉本期内容对你有帮助,欢迎点赞,关注,收藏Thanks♪(・ω・)ノ