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信号
{
    //自定义操作
}


目录
相关文章
|
传感器 安全
第四问:QT中信号和槽原理
Qt的信号与槽机制是观察者模式的典型实现,允许对象间通信而不直接依赖。信号用于通知事件发生,槽是响应信号的函数,通过`QObject::connect()`连接。这种机制实现了松耦合、灵活扩展和自动通知,适用于UI更新和数据绑定等场景。
|
C++
003 Qt_信号和槽-上
本文介绍了Qt中的信号与槽机制,包括信号和槽的概念、本质及连接方法,并演示了如何自定义槽函数。信号是事件的体现,槽是对信号的响应函数。通过信号与槽,可以将独立的控件关联起来,实现复杂的交互逻辑。文中还详细展示了如何在Qt项目中定义和使用槽函数,通过实例代码和图形化界面操作,帮助读者更好地理解和应用这一机制。
471 1
003 Qt_信号和槽-上
|
编译器
(9)Qt中信号与槽重载的解决方案
本文介绍了在Qt中处理信号与槽重载问题的三种解决方案:使用函数指针、Qt提供的QOverload类和Qt4的宏方式。
960 3
(8)Qt中的自定义信号
本文介绍了如何在Qt框架中创建和使用自定义信号,并通过一个父子窗口切换的示例来展示自定义信号的实现和应用。
612 3
(8)Qt中的自定义信号
【qt】有点意思的信号与槽
【qt】有点意思的信号与槽
168 0
【qt】QTcpSocket相关的信号
【qt】QTcpSocket相关的信号
290 0
|
程序员 C++
【Qt】信号与槽(下)
【Qt】信号与槽(下)
|
Linux C++
【Qt】信号与槽(上)
【Qt】信号与槽(上)
【Qt】信号与槽(上)
Qt中的信号与槽如何学习?(包括自定义信号)这篇文章告诉你
以现实中的事件来举例的话,例如有两把不同颜色的信号枪,分别是红色,绿色,打响不通颜色的信号枪会触发不同的槽发生,比如说打响红色这个人就跑步,绿色就走步,但是还有一个很重要的机制,那就是连接,我们需要把信号枪去跟这个人的动作连接起来。 如果上面理解没问题的话我们可以把信号和槽看成两个工具,我们最重要的是如何去把这两个工具连接起来。 它的作用可以让我们更加灵活的去使用不同窗口间的切换以及某些事件的连接。
446 1
Qt信号和槽
Qt信号和槽
194 2