目录
[4. 带参数的信号与槽](#4. 带参数的信号与槽)
[7.使⽤ Lambda 表达式定义槽函数](#7.使⽤ Lambda 表达式定义槽函数)
接下来的日子会顺顺利利,万事胜意,生活明朗-----------林辞忧
基本概念
1.在 Qt 中,⽤⼾和控件的每次交互过程称为⼀个事件,每个事件都会发出⼀个信号, Qt 中的所有控件都具有接收信号的能⼒,⼀个控件还可以接收多个不同的信号。对于接收到的每个信号,控件都会做出相应的响应动作,在 Qt 中,对信号做出的响应动作就称之为槽。
2.信号的三个要素:
信号源:由哪个控件发出的信号
信号的类型:用户进行不同的操作,就可能触发不同的信号
信号的处理方式:槽,本质是函数, 槽函数可以与⼀个信号关联,当信号被 发射时,关联的槽函数被⾃动执⾏。在Qt中使用connect函数,把一个信号和槽关联起来,后续只要信号触发,Qt就会自动的执行槽函数,槽函数本质就是回调函数
3.信号函数和槽函数通常位于某个类中,和普通的成员函数相⽐,它们的特别之处在于:
信号函数⽤ signals 关键字修饰,槽函数⽤ public slots、protected slots 或者 private slots 修
饰。signals 和 slots 是 Qt 在 C++ 的基础上扩展的关键字,专⻔⽤来指明信号函数和槽函数;
4.信号函数只需要声明,不需要定义(实现),⽽槽函数需要定义(实现)
5. 信号函数的定义是 Qt ⾃动在编译程序之前⽣成的. 编写 Qt 应⽤程序的程序猿⽆需关注.
这种⾃动⽣成代码的机制称为 元编程
信号与槽的使用
1.在Qt中一定是先关联信号与槽,然后再触发这个信号,顺序不能颠倒,否则信号就不知道如何处理了
2.connect函数是QObject这个类提供的静态成员函数
3.Qt中提供的类,本身是存在一定的继承关系的,Qt 中提供的很多类都是直接或者间接继承⾃ QObject
4.connect() 函数原型:
5.举例: 在窗⼝中设置⼀个按钮,当点击 "按钮" 时关闭 "窗⼝" ,针对button点击,Widget就会关闭
一些注意点:
在connect函数原型当中,第1和第3个参数的类型都是QObject*,而这里一个是QPushButton*和Widget*,在上面就提到Qt中提供的类都是直接或间接继承QObject类的,所以根据c++继承中父子类的切片规则,子类对象是可以直接传给父类对象的
对于第2和第4个参数的类型都是函数指针,而原型中都是char*,此时根据常识这两个类型的传递是不匹配的,因此这里采用了转化的机制
先查看官方文档中对connect的声明
这个是旧版本的connect的实现,此时给信号参数传参,要搭配一个SIGNAL宏,给槽函数传参要搭配一个SLOT宏来实现函数指针转为char*
但经过后来重载改变后,在文档这里是查看不出啥的,这样就需要在代码中点击connect,再按Ctrl+鼠标左键,查看connect函数的实现
在重载版本当中,就不需要写SIGNAL和SLOT宏了,而是将第2和第4个参数变为了泛型参数,允许传入任意类型的函数指针
6.查看内置的信号与槽
系统⾃带的信号和槽通常是通过 "Qt 帮助⽂档" 来查询,寻找关键字 signals来查询信号
自定义信号和槽函数
1.通过代码来自定义槽函数
2.通过QtCreator生成信号槽代码
先用PushButton控件来创建一个窗口,再点击右键转换到槽
双击之后就转换到这里
在这里QtCreator直接生成好了一个函数
在执行过程中,这个函数会调用connectSlotsByName函数
3.自定义信号
(1)Widget类继承了QWidget和QObject类,这两个类中已经提供了一些信号了,可以直接使用
(2)Qt中的信号是一类非常特殊的函数
( 3)我们自己定义的信号,只需要写出函数声明,并且告诉Qt这是一个信号。而函数的定义,是Qt在编译的过程中自动生成的
(4)作为信号函数,这个函数的返回值必须是void,有没有参数都可以,还支持重载
(5)在写信号函数声明时,必须添加Qt关键字signals。在qmake的时候,调用一些代码的分析/生成工具,在扫描到类中包含signals关键字时,就会自动的把下面的函数声明认为是信号,并且自动的给这些信号函数生成对应的定义
在建立连接之后,必须要发射信号,Qt内置的信号是不需要自己通过代码手动来触发的,用户在GUI进行某些操作时,就会自动触发对应的信号(发射信号的代码已经内置在Qt框架中了)
先后执行顺序
4. 带参数的信号与槽
(1)当信号带有参数的时候,槽的参数必须和信号的参数一致。此时发射信号的时候,就可以给信号函数传递实参,与之对应的这个参数就会被传递到对应的槽函数当中
这里的一致是参数类型要一致,个数可以不一致,不一致的时候要求信号的参数的个数必须要比槽的参数个数要多
(2) 信号函数的参数个数只要>=槽函数的参数个数,就可以正常使用,否则就会编译报错
这是为啥允许信号参数个数比槽函数的多呢? 一个槽函数可能会绑定多个信号,如果我们严格要求参数个数一致,就意味着信号绑定到槽的要求变高了,换言之,当下的这种规则,信号与槽之间的绑定就更加灵活了,更多的信号就可以绑定到槽函数上了
当个数不一致时,槽函数就会按照参数顺序,拿到信号的前N个参数,这样就至少确保槽函数的每个参数都是有值的
(3)Q_OBJECT宏
这个宏展开会得到一系列的复杂代码,会涉及到Qt的实现。如果不加这个宏,就会编译报错
5.意义
所谓的信号槽本质就是要响应用户的操作
(1)解耦合,把触发用户操作的控件和处理对应用户的操作逻辑解耦合
(2)实现多对多的效果。一个信号可以connect到多个槽函数上;一个槽函数也可以被多个信号connect.但在实际的开发过程中很多都是用到一对一的(一个事件只能对应一个处理函数)
6.信号与槽的断开
使用disconnect来断开信号槽的连接。disconnect 的⽤法和 connect 基本⼀致。主动断开往往是把信号连接到另一个槽函数上
7.使⽤ Lambda 表达式定义槽函数
(1)lambda表达式本质是一个回调函数,一次性使用,无法直接获取上层作用域的变量,为了解决这个问题,引入了变量捕获语法,通过变量捕获,获取到外层作用域中的变量
也可以写为
写作[=]的含义就是把上层作用域中所有的变量名给捕获进来
(2)早期版本的 Qt,若要使⽤Lambda表达式,要在 ".pro" ⽂件中添加: CONFIG += C++11