Qt | 信号和槽的一些总结

简介: 学习使用Qt的信号槽机制。

前言:

信号和槽用于两个对象之间的通信,信号和槽机制是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信号
{
    //自定义操作
}


目录
相关文章
|
12天前
|
编译器
(9)Qt中信号与槽重载的解决方案
本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。
47 3
|
5月前
|
存储 安全 编译器
【Qt 底层机制之信号和槽 】深入探究Qt信号和槽背后的原理
【Qt 底层机制之信号和槽 】深入探究Qt信号和槽背后的原理
1700 4
|
5月前
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
【Qt 学习笔记】按钮实现helloworld | 信号与槽概述
74 0
|
5月前
|
编译器 C++ 开发者
QT基础【7-跨进程发送信号】
QT基础【7-跨进程发送信号】
|
5月前
|
开发者
QT基础【6-跨界面发送信号】
QT基础【6-跨界面发送信号】
|
5月前
|
存储 API C++
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
【Qt 信号槽】深入探索 Qt 信号和槽机制中的引用传递“ (“A Deep Dive into Reference Passing in Qt Signal and Slot Mechanism“)
478 0
|
5月前
|
安全 编译器 开发者
【Qt 学习笔记】Qt信号和槽的其他说明及Lambda表达式
【Qt 学习笔记】Qt信号和槽的其他说明及Lambda表达式
176 0
|
12天前
(8)Qt中的自定义信号
本文介绍了如何在Qt框架中创建和使用自定义信号,并通过一个父子窗口切换的示例来展示自定义信号的实现和应用。
39 3
(8)Qt中的自定义信号
|
4月前
|
安全 C++ Windows
Qt信号与槽机制
Qt信号与槽机制
47 1
|
2月前
|
程序员 C++
【Qt】信号与槽(下)
【Qt】信号与槽(下)