Qt学习笔记:信号和槽机制

在GUI编程中,经常希望一个部件的状态改变能够引起另一个部件的注意,也就是实现部件之间的通信。传统的方法是采用回调函数。回调(callback)的本质是将一个预先定义的函数通过函数指针的方式传递给另一个函数,让它在合适的时候通过指针调用该函数。举一个简单的例子:

#include <stdio.h> 
void clicked(int k)
{
    printf("#%d: I'm clicked\n", k);
}

void kicked(int k)
{
    printf("#%d: I'm kicked\n", k);
}

void callback(void(*pt) (int k), int k)
{
    (*pt)(k);
}

int main()
{
    for (int i = 0; i<10; ++i)
    {
        if (i % 3 == 0)
        {
            callback(clicked, i);
        }
        else
        {
            callback(kicked, i);
        }
    }
    return 0;
}

回调函数存在的主要问题在于不保证传入参数类型的正确性,所以不是类型安全的。而Qt采用了一种信号(signal)和槽(slot)的机制,替代回调函数,实现部件之间的通信。信号/槽是类型安全的,因为信号和槽的函数签名必须一致,否则编译器就会报错(实际上槽的签名可能更短,它会忽略额外参数)。

所有包含信号/槽的类,都必须直接或间接继承于QObject,并且在声明时加上宏Q_OBJECT。在对象状态改变时,信号就会产生,另一个对象具有接收该信号的槽,从而实现了两个对象之间的通信。只要信号与槽的签名匹配,就可以连接,而信号发出者不知道它的信号将由那些对象接收,同样地,槽只知道接收到信号,不关心信号是谁发出的。如图所示,一个信号可以连接多个槽,一个槽也可以接收多个信号。信号发出时,接收该信号的slot按照connect的顺序,依次执行,直到所有的slot都返回,才继续执行后面的程序。
这里写图片描述

使用函数connect即可完成信号和槽的连接,如需解除连接,则使用disconnect函数

connect(scrollbar, SIGNAL(valueChanged(int)), mainwindow, SLOT(function(int)));

对于含有默认参数的信号和槽,例如:QObject::destroyed()和QObject::objectDestroyed()

void destroyed(QObject* = 0);//signal
void objectDestroyed(QObject* obj = 0);//slot

以下几种连接方式均合法:

connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
connect(sender, &QObject::destroyed, [=](){ this->m_objects.remove(sender); });
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed(Qbject*)));
connect(sender, SIGNAL(destroyed(QObject*)), this, SLOT(objectDestroyed()));
connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed()));

但是以下这种连接不合法:

connect(sender, SIGNAL(destroyed()), this, SLOT(objectDestroyed(QObject*)));

在这种情况下,slot会等待signal传递一个QObject,但signal根本不会传这样一个参数过来,所以会引起一个runtime error。

Qt的信号/槽机制由Qt的元对象系统(meta-object system)支持,信号由元对象编译工具(meta-object compiler, moc)自动定义,不能在.cpp文件中自己写实现,也没有任何返回值。Qt已经为QObject及其子类预定义了一些信号,直接使用即可。而槽就是普通的函数,按照通常的函数定义和调用即可。

与回调相比,信号/槽比较灵活,但是没有回调快。Qt文档中的描述是:

In general, emitting a signal that is connected to some slots, is approximately ten times slower than calling the receivers directly, with non-virtual function calls.
(通常来说,发出一个到所连接槽的信号,大约比直接调用一个接收函数慢10倍)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章