Qt信号与槽

1.信号和槽概述

信号槽是 Qt 框架引以为豪的机制之一。所谓信号槽,实际就是观察者模式(发布-订阅模式)。当某个事件发生之后,比如,按钮检测到自己被点击了一下,它就会发出一个信号(signal)。这种发出是没有目的的,类似广播。如果有对象对这个信号感兴趣,它就会使用连接(connect)函数,意思是,将想要处理的信号和自己的一个函数(称为槽(slot))绑定来处理这个信号。也就是说,当信号发出时,被连接的槽函数会自动被回调。这就类似观察者模式:当发生了感兴趣的事件,某一个操作就会被自动触发

1.1 信号的本质 

        信号是由于用户对窗口或控件进行了某些操作,导致窗口或控件产生了某个特定事件,这时候Qt对应的窗口类会发出某个信号,以此对用户的挑选做出反应:

        因此根据上述的描述我们得到一个结论 – 信号的本质就是事件,比如:

  • 按钮单击、双击
  • 窗口刷新
  • 鼠标移动、鼠标按下、鼠标释放
  • 键盘输入

那么在Qt中信号是通过什么形式呈现给使用者的呢?

  • 我们对于哪个窗口进行操作,哪个窗口就可以捕捉到这些被触发的事件
  • 对于使用者来说触发了一个事件我们就可以得到Qt框架给我们发出的某个特定信号
  • 信号的呈现形式就是函数,也就是说某个事件产生了,Qt框架就会调用某个对应的信号函数,通知使用者

在QT中信号的发出者是某个实例化的类对象,对象内部可以进行相关事件的检测

1.2 槽的本质

        在Qt中槽函数是一类特殊的功能的函数,在编码过程中也可以作为类的普通成员函数来使用。之所以称之为槽函数是因为它们还有一个职责就是对Qt框架中产生的信号进行处理:

举个简单的例子:

    女朋友说:“我肚子饿了!”,于是我带她去吃饭。

上边例子中相当于女朋友发出了一个信号, 我收到了信号并其将其处理掉了。

实例对象 角色 描述
女朋友 信号发出者 信号携带的信息:我饿了
信号接收者

处理女朋友发射的信号:带她去吃饭

在Qt中槽函数的所有者也是某个类的实例对象

1.3 信号和槽的关系

        在Qt中信号和槽函数都是独立的个体,本身没有任何联系,但是由于某种特性需求我们可以将二者连接到一起,好比牛郎和织女想要相会必须要有喜鹊为他们搭桥一样。在Qt中我们需要使用QOjbect类中的connect函数进二者的关联。

连接信号和槽的connect()函数原型如下, 其中PointerToMemberFunction是一个指向函数地址的指针

QMetaObject::Connection QObject::connect(
    	const QObject *sender, PointerToMemberFunction signal, 
        const QObject *receiver, PointerToMemberFunction method, 
		Qt::ConnectionType type = Qt::AutoConnection);
参数:
  - sender:   发出信号的对象
  - signal:   属于sender对象, 信号是一个函数, 这个参数的类型是函数
              指针, 信号函数地址
  - receiver: 信号接收者
  - method:   属于receiver对象, 当检测到sender发出了signal信号, 
              receiver对象调用method方法,信号发出之后的处理动作
 
//  参数 signal 和 method 都是函数地址, 因此简化之后的 connect() 如下:
connect(const QObject *sender, &QObject::signal, const QObject *receiver, &QObject::method);
  •  connect函数相对于做了信号处理动作的注册
  • 调用conenct函数的sender对象的信号并没有产生, 因此receiver对象的method也不会被调用
  •  method槽函数本质是一个回调函数, 调用的时机是信号产生之后, 调用是Qt框架来执行的
  • connect中的sender和recever两个指针必须被实例化了, 否则conenct不会成功

1.4 信号与槽在使用中的注意事项

(1)要使用的信号(发送者)和槽(接收者)的类必须要间接或直接继承QObject类,还必须要在类的定义中的第一行写上一个宏定义Q_OBJECT

(2)当信号与槽函数的参数数量相同时,它们的参数类型必须要一致(信号的参数不能少于槽函数的参数)

        如果信号的参数与槽函数不一致时,有两种解决方法:

        方法1:强制转换 static_cast<>(object);

        方法2:QOverLoad::of(object);

(3)如果信号和槽函数的参数不一致,允许的情况是,槽函数的参数可以比信号的参数少,但是,槽函数存在的那些参数的顺序也必须和信号前面几个类型一致

(4)信号和槽函数的参数必须是元对象类型,如果不是就要注册该类型,使用Q_DECLARE_METATYPE(Type)宏

(注册自定义类型的方法请看我写的这篇博客Qt中的基础数据类型_lune_one的博客-CSDN博客)

(5)发送对象和接收对象要对应(信号的发送者和接收者关联的对象不匹配时,就会解除关联,其中一个释放,也会解除关联)

(6)信号和槽函数的返回值都是void

(7)信号只需要声明,不需要实现;槽函数需要声明与需要实现

(8)一个信号可以关联多个槽,多个信号可以关联同一个槽

(9)一个信号可以关联一个信号

(10)槽可以被取消关联(disconnect)

1.5 信号与槽的优缺点

优点:(1)类型安全 (2)松散耦合 (3)灵活性

(1)类型安全:信号的参数类型和参数个数相同,接受该信号的槽的参数类型和参数个数相同。若信号和槽签名不一致,编译器会报错

(2)松散耦合:信号发送者和接收者是独立的。信号和槽之间实现了异步关系,信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无需知道是那个对象的那个信号槽接收它发出的信号,它只需在适当的时间发送适当的信号即可,而不需要关心是否被接受和那个对象接受了。Qt就保证了适当的槽得到了调用,即使关联的对象在运行时被删除。程序也不会奔溃

(3)灵活性:一个信号可以关联多个槽,多个信号可以关联同一个槽

 缺点:(1) 效率低

信号与槽速度较慢。与回调函数相比,信号和槽机制运行速度比直接调用非虚函数慢 10倍

原因∶

1)需要定位接收信号的对象。

2)安全地遍历所有关联槽。

3)编组、解组传递参数。

4)多线程的时候,信号需要排队等待。

 1.6 信号与槽关联函数connect的第五个参数 连接类型

connect(sender, signal, receiver, slot, connection type);

connect(信号发出者,信号,信号接收者,槽,连接类型(隐藏默认为自动连接))

(1)Qt::AutoConnect(自动关联)

        默认值,连接类型会在信号发送时确定。如果接收者和发送者在同一个线程,则自动使用Qt::DirectConnection(直接连接)类型,如果接收者和发送者不在同一个线程

你可能感兴趣的:(qt,开发语言)