当前位置:网站首页>Qt | 信号和槽的一些总结
Qt | 信号和槽的一些总结
2022-08-02 14:41:00 【华为云】
前言:
信号和槽用于两个对象之间的通信,信号和槽机制是 Qt 的核心特征。在使用信号和槽时,一个信号可以关联到多个槽上,多个信号也可以关联到同一个槽上,一个信号还可以关联到另一个信号上。如果是一个信号关联多个槽,这些槽会一个接一个地执行,执行顺序与关联顺序相同。
之前遇到一个面试题:
如果同一个信号和同一个槽函数进行了多次连接(connect),是否会造成崩溃?
答案是不会,如果同一个信号和同一个槽函数进行多次连接,那么信号在发出后,会多次执行槽函数。
信号和槽详解:
声明一个信号需要使用 signals 关键字,在 signals 前面不能添加 public、private、protected 等限定符。信号默认是 public 的,可以在任何地方进行发射(emit),但是建议只在定义该信号的类及其子类中进行发射改信号。
信号只用声明,不需要实现。而且,信号没有返回值,只能是 void 类型的。
只有 QObject 类及其子类派生的类才可以使用信号和槽机制。使用信号和槽还必须在类声明的最开始处添加 Q_OBJECT 宏。
槽就是普通的 C++函数,可以像一般函数一样使用。声明槽要使用 slots 关键字,一个槽可以是 private、public 或者 protected 类型的,也可以被声明为虚函数。
槽函数中的参数的类型和信号参数的类型要相对应,且不能比信号的参数多。
connect 详解:
第一个参数为发射信号的对象。
第二个参数为要发射的信号。
第三个参数为接收信号的对象。
第四个参数为要执行的槽。
第五个参数 type 为关联的方式。
Qt::AutoConnection: 自动关联,默认值。如果 receiver 于发射信号在同一线程,则该类型表示 Qt::DirectConnection;否则,该类型表示 Qt::QueuedConnection。在信号被发射时决定表示那种类型。
Qt::DirectConnection: 直接关联。发射完信号后立即调用槽函数,只有槽函数执行完成返回后,发射信号后面的代码才会执行。
Qt::QueuedConnection: 队列关联。当控制返回 receiver 所在线程的事件循环后再执行槽函数,无论槽函数是否执行,发射信号后面的代码都会立即执行。
Qt::BlockingQueuedConnection: 阻塞队列关联。类似 Qt::QueuedConnection,不过,信号线程会一直阻塞,知道槽函数返回。当 receiver 存在于信号线程时不能使用该类型,不然程序会死锁。
Qt::UniqueConnection: 唯一关联。这是一个标志,可以结合其他几种连接类型,使用按位或操作。这时两个对象间的相同的信号和槽只能有唯一的关联。使用这个类型主要是为了防止重复关联。
Qt5 之前的形式: connect(dlg, SIGNAL(funcSignal(int)), this, SLOT(funcSlot(int)));
Qt5 加入的一种形式: connect(dlg, &MyDialog::funcSignal, this, &Widget::funcSlot);
使用 Qt5 的这种形式的一个好处就是可以再编译时进行检查,信号或槽的拼写错误、槽函数参数数目多于信号的参数数目等错误都会在编译时发现。
另外,这种形式还支持 C++11 中的 Lambda 表达式,可以在关联时直接编写信号发射后要执行的代码,例如:
connect(dlg, &MyDialog::funcSignal, [=](int value){ui->label->setText(QString::number(value))});
信号和槽的自动关联:
槽函数:on_“部件的 objectName”_“信号名称”。
以这种方式命名的槽函数可以直接和信号关联,不用再使用 connect()函数。
connectSlotsByName()函数是用来支持信号和槽自动关联的,因为 setupUi()函数中自动调用了 connectSlotsByName()函数,所以要使用自动关联的部件的定义都要放在 setupUi()函数调用之前,且必须使用 setObjectName()指定它们的 objectName,只有这样才能正常使用自动关联。
断开关联 disconnect:
断开与一个对象多有信号的所有关联:disconnect(myObject, 0, 0, 0); 等价于 myObject->disconnect();
断开与一个指定信号的所有关联:disconnect(myObject, SIGNAL(mySignal()), 0, 0);等价于 myObject->disconnect(SIGNAL(mySignal()));
断开与一个指定的 receiver 的所有关联:disconnect(myObject, 0, myReceiver, 0); 等价于 myObject->disconnect(myReceiver);
断开一个指定信号和槽的关联:disconnect(myObject, SIGNAL(mySignal()), myReceiver, SLOT(mySlot())); 等价于 myObject->disconnect(SIGNAL(mySignal()), myReceiver, SLOT(mySlot()));还等价于 disconnect(myConnection);//myConnection 是进行关联时 connect()的返回值。
disconnect 也可以使用基于函数指针的重载形式,及 Qt5 后添加的不需要 SIGNAL()和 SLOT()宏的形式。
关于信号槽的高级应用:
Qt 提供了 QObject::sender() 函数来返回发送该信号的对象的指针。
有时存在多个信号关联到同一个槽上的情况,此时如果想在槽函数中对某个信号进行特殊处理,就可以通过 QObject::sender()来获取信号的对象指针,来进行判断是否是我们需要特殊处理的对象。
如果在多个信号关联到同一个槽上,而在该槽中需要对每一个信号进行不同的处理,可以使用 QSignalMapper 类。QSignalMapper 被叫做信号映射器,可以实现对多个相同部件的相同信号进行映射,为其添加字符串或者数值参数,然后再发射出去。
QSignalMapper 使用举例:
QSignalMapper *signalMapper = new QSignalMapper(this);
for (i = 0; i < 5; i++)
{
QPushButton *button = new QPushButton(this);
connect(button, SIGNAL(clicked()), signalMapper, SLOT(map()));
signalMapper->setMapping(button, i);
}
connect(signalMapper, SIGNAL(mapped(int)), this, SLOT(handle(int)));
然后槽中可以这样写:
switch(i) //i表示是哪个button发生了clicked信号
{
//自定义操作
}
边栏推荐
- 2022-07-29 第六小组 瞒春 学习笔记
- 中国服装行业已形成一套完整的产业体系
- Redis最新6.27安装配置笔记及安装和常用命令快速上手复习指南
- setTimeout与setInterval的区别
- 线程安全问题以及其解决方法
- 统计二进制中1的个数,两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?
- 2022 Low Voltage Electrician Exam Questions and Online Mock Exam
- Servlet运行原理_API详解_请求响应构造进阶之路(Servlet_2)
- 数据库三范式
- form的编辑与展示的切换(输入框,单选多选框,上传图片,颜色选择器)适用个人信息的展示与修改
猜你喜欢
随机推荐
多线程------实际篇
2022-07-23 第六小组 瞒春 学习笔记
this beta version of Typora is expired, please download and install a newer version.Typora的保姆级最新解决方法
Apache APISIX 2.15 版本发布,为插件增加更多灵活性
PAT tree DP (memory search) class a, 1079, 1090, 1106
散列表简述
数组的应用实例—三子棋
2022年低压电工考试试题及在线模拟考试
BSC链智能合约模式系统开发功能逻辑分析
2022-07-26 第六小组 瞒春 学习笔记
【Untitled】
第三章-函数的增长-3.1-渐近记号
MySQL (2)
leetcode 504. Base 7 七进制数 (简单)
一文让你快速手写C语言-三子棋游戏
form的编辑与展示的切换(输入框,单选多选框,上传图片,颜色选择器)适用个人信息的展示与修改
“绿色低碳+数字孪生“双轮驱动,解码油气管道站升级难点 | 图扑软件
CNN鲜花分类
该死的单元测试,写起来到底有多痛?
Drag and Drop in H5