?博客主页: 小羊失眠啦.
?系列专栏:《C语言》 《数据结构》 《C++》 《Linux》 《Qt》
❤️感谢大家点赞?收藏⭐评论✍️
一、什么是信号与槽
信号槽,是Qt的核心机制,用来实现对象之间的通信: 即,某个对象,想通知另一个对象去做某件事情时, 这个对象,就发送某个“信号”, 另一个对象收到这个信号后,就去做之前约定好的那个 特定的事情。
信号槽机制有:
1)信号的发送者
2)信号的接受者
3)发送者发送的这个信号(不需要程序员去定义函数体的空壳函数)
4)接收者去执行的某个函数(称为:槽)
我们要做:
1.信号槽需要在使用之前,做好关联(信号和槽之间的关联)
2.发送者在需要的时候,发送这个信号
问题:为什么不直接使用C/C++的回调函数,而去使用信号槽?
1)信号与槽,是松耦合的,信号发送者,不需要去了解接收者的具体信息(有哪些接口等) 回调函数,是紧密耦合,直接调用目标对象的特定函数。
2)信号槽,比回调函数,使用起来更灵活。
信号与槽缺点
使用信号槽,比使用回调函数,运送速度慢: 信号与槽函数执行,可能是异步的(仅使用直连方式连接信号槽时,槽函数才会被同步执行,执行完之后,发送信号(emit)语句之后的代码才会被执行。
使用回调函数,都是同步方式执行的。
二、信号与槽的关联
2.1 connect函数
写法一
使用SIGNAL和SLOT,把信号和槽转换成constchar*字符串
注意:
使用connect关联时,信号和槽,如果有参数,必须带上参数的类型(不需要带参数变量)
可以把QObject::省略,因为MainWindow本身就是QObject的子类,可以直接使用父类的方法。
信号和槽不需要、也不能使用类名进行限定,直接写函数名以及新参列表即可。
写法二
直接使用信号和槽函数的地址,但是要求: 信号和槽的参数个数相同,而且能够进行合适的隐式类型转换,合作就会编译失败
注意:该方式,信号和槽,需要使用类名进行限定!
合法使用:
MainWindow::MainWindow(QWidget*parent) :QMainWindow(parent) ,ui(newUi::MainWindow) { ui->setupUi(this); connect(ui->lineEdit, &QLineEdit::textChanged, ui->label, &QLabel::setText); }
2.2 自动连接
在QtCreator 的设计器中,右键单击控件,选择“转到槽”
再选择信号
然后自动生成一个空的槽函数(自动生成这个槽函数的声明和一个空的实现):on_信号发送者的对象名_信号名
槽函数的具体实现,需要自己完成。
注意: 也可以直接按照 这个命名规则手写一个槽函数,就可以实现信号槽的关联! Qt 框架,会通过这个槽函数的命名,来自动识别信号的发送者、信号名 (程序员一般不使用这个方式,虽然是支持的,因为容易出错,而且比较麻烦)
注意:
这种方式连接的信号槽,必须在槽函数对应的访问权限后加 slots
通过connect 连接的信号槽,对应的槽函数不需要使用slots
三、定义信号
自定义信号,如上图所示(上位机项目代码片段) 自定义信号,必须使用signals:
信号,只是一个特殊的空函数,不需要对应的函数体实现。
信号的参数个数,可以大于槽函数的参数个数,但是不能少于槽函数的参数个数。
编译器在构建的时候,扫描到signals, 就会生成 moc_*.cpp文件
四、定义槽
普通的槽(槽函数),和普通函数一样,不需要特殊设置。
使用设计器自动生成的槽函数,必须使用宏slots,而且这个槽函数的命名,必须遵循“on_ 对象名_信号名”的规则。 (这种信号槽,不需要使用connect进行手动关联)
五、发送信号
自动发送信号
Qt 的组件,在用户操作时,能自动发送对应的型号,例如按钮点击后,自动发送clicked() 信号
用代码手动发送信号
也可以使用emit手动发送信号: 相当于在pushButton按钮上点击了一下,即让这个按钮发送click信号
emit ui->pushButton->clicked();
六、信号与槽连接方式
使用connect 进行信号和槽的关联时,还有第5个参数,表示具体的连接方式。 该参数的默认参数是:Qt::AutoConnection 自动连接
6.1 直接连接 Qt::DirectConnection
效果类似于“函数调用”,同步执行: 使用emit发送信号后,槽函数被直接调用,调用完成之后,再执行emit之后的语句。
6.2 队列连接 Qt::QueuedConnection
效果类似于“异步函数调用”。 当信号发出后,信号被添加到“信号队列”中, 需等到接收对象所属线程的事件循环取得控制权时才取得该信号,再调用相应的槽函数。 emit 发送信号后,直接执行emit后面的代码,不需要等待槽函数执行完毕。
6.3 阻塞队列连接 Qt::BlockingQueuedConnection
与队列连接的基础上,加上阻塞发送信号所在的线程。
用于在不同线程之间进行对象之间的通信。 它可以确保发送者在发出信号后立即等待接收者处理完槽函数后才继续执行。 当信号被触发时,发送者会阻塞直到接收者处理完对应的槽函数,并且该槽函数会在接收者所属的线程中执行。 这种连接类型适用于需要不同线程需要同步处理的情况。
6.4 自动连接 Qt::AutoConnection
如果发送信号和接收者在同一线程,就等效与:直接连接方式 如果发送信号和接收者不在同一线程,就等效与:队列连接默认的连接方式。
6.5 Qt::UniqueConnection
不能单独使用,需要和其他类型组合使用, 用来确保指定的发送者、指定的信号、指定的接受者、指定的槽,只存在唯一的一种连接。 即用来避免:
避免信号和槽,以某种方式连接后,然后又调用connect以另一种方式连接避免建立多个重复的信号槽后,一个信号,将导致重复发送多个信号定义自己的槽函数时,如果不使用slots, 那么使用connect进行信号和槽的连接时,必须 使用“方式2”(使用&取信号和槽的地址),如果使用SIGNAL和SLOT宏,会关联失败。 为了方便起见,定义自己的槽函数时,最好还是都加上slots。
七、对应关系
同一个信号,可同时关联多个槽。 多个信号,可关联到同一个槽。
如果一个信号连接到多个槽,当信号发出时,槽函数按照连接建立的顺序被调用
默认情况下,每个连接都会发出一个信号;对于重复的连接发出多个信号。可以通过一 个disconnect()调用中断所有这些连接
八、断开
实例
执行效果
断开指定的信号槽
disconnect 的其它用法
nullptr可以作为通配符,分别表示“任何信号”、“任何接收对象”或“接收对象中 的任何槽”
7a52d8f031f6.png)
断开指定的信号槽
disconnect 的其它用法
nullptr可以作为通配符,分别表示“任何信号”、“任何接收对象”或“接收对象中 的任何槽”