深入探索QT中的信号与槽函数

相信有过一点QT开发经验的人来说,对于QT中的信号并不陌生。在一个实际的QT项目当中,大多时候是直接将组件中预定义的信号连接到槽函数,当信号发送的时候槽函数就被调用。那么QT中的信号具体又是怎么来的呢?信号又是如何发射的呢?

QT中信号(SIGNAL)的本质

-信号只是一个特殊的成员函数的声明

.函数的返回值是void类型

.函数只能声明不能定义

-信号必须使用signals关键字进行声明

.函数的访问属性自动被设置为protected

.只能通过emit关键字调用函数(发射信号)

下面来看一下信号定义的实例:

class Test:public QObject   //只有Qt类才能定义信号
{
    Q_OBJECT                //必须使用宏 Q_OBJECT
    
signals:                    // 使用signal声明信号函数   
    void testSignal(int v); // 访问级别自动被设置为protected
                            // 信号只能声明不能定义
public:
    void test(int i)
    {
        emit  testSignal(i); // 通过emit发射信号
    }
};

信号与槽函数的映射方式:

1.可以一个信号映射一个槽函数,例如:A对象的signal1 映射到 B对象的slot1

2.可以多个信号映射一个槽函数,例如:A对象的signal1 和 D对象的signal3 映射到 B对象的slot1

3.可以一个信号映射到多个槽函数,例如:E对象的signal5 映射到 C对象的 slots3 和 B对象的 slot2

4.还可以存在信号从一个对象转嫁到另外一个对象。例如:D对象的 signal4 映射到 E对象的 signal6,然后转嫁到 C对象的 slots4

5.信号与槽函数的连接可以被 disconnect函数删除 (移除)

下面通过实际的程序实例来验证上面的原理:

#ifndef TESTSIGNAL_H
#define TESTSIGNAL_H

#include 

class TestSignal : public QObject
{
    Q_OBJECT
public:
    void send(int i)
    {
        emit testSignal(i);
    }
signals:
    void testSignal(int i);
    
};

#endif // TESTSIGNAL_H
#ifndef RXCLASS_H
#define RXCLASS_H

#include 
#include 

class RxClass : public QObject
{
    Q_OBJECT
public:
    
protected slots:
    void mySlot(int v)
    {
        qDebug()<<"void mySlot(int v)";
        qDebug()<<"sender:"<objectName();
        qDebug()<<"Receiver:"<objectName();
        qDebug()<<"value:"<
#include 
#include "TestSignal.h"
#include "RxClass.h"

void emit_signal()
{
    qDebug()<<"void emit_signal()";

    TestSignal t;
    t.setObjectName("t");
    RxClass r;
    r.setObjectName("r");

    QObject::connect(&t,SIGNAL(testSignal(int)),&r,SLOT(mySlot(int)));

    for(int i=0;i<3;i++)
    {
        t.send(i);

    }
}

void one_multi()
{
    qDebug()<<"void one_multi()";

    TestSignal t;
    RxClass r1;
    RxClass r2;

    t.setObjectName("t");
    r1.setObjectName("r1");
    r2.setObjectName("r2");

    QObject::connect(&t,SIGNAL(testSignal(int)),&r1,SLOT(mySlot(int)));
    QObject::connect(&t,SIGNAL(testSignal(int)),&r2,SLOT(mySlot(int)));

    for(int i=0;i<3;i++)
    {
        t.send(i);
    }
}

void multi_one()
{
    qDebug()<<"void multi_one()";

    TestSignal t1;
    TestSignal t2;
    RxClass r;

    t1.setObjectName("t1");
    t2.setObjectName("t2");
    r.setObjectName("r");


    QObject::connect(&t1,SIGNAL(testSignal(int)),&r,SLOT(mySlot(int)));
    QObject::connect(&t2,SIGNAL(testSignal(int)),&r,SLOT(mySlot(int)));

    t1.send(100);
    t2.send(101);
}

void signal_to_signal()
{
    qDebug()<<"void signal_to_signal()";

    TestSignal t1;
    TestSignal t2;
    RxClass r;

    t1.setObjectName("t1");
    t2.setObjectName("t2");
    r.setObjectName("r");


    QObject::connect(&t1,SIGNAL(testSignal(int)),&t2,SIGNAL(testSignal(int)));
    QObject::connect(&t2,SIGNAL(testSignal(int)),&r,SLOT(mySlot(int)));

    t1.send(100);
    t2.send(101);
}

int main(int argc, char *argv[])
{
    QCoreApplication a(argc, argv);

    //emit_signal();
    //one_multi();
    //multi_one();
    signal_to_signal();
    
    return a.exec();
}

在用QT开发的时候不可忽视的军规:

1.Qt类只能在头文件中声明 (一个普通的C++类,并没有这种要求)

2.信号与槽函数的原型应该完全相同

3.信号参数多余槽函数参数时候,多余的槽函数被忽略

4.槽函数的返回值必须是void类型

5.槽函数可以像普通成员函数一样被调用

6.信号与槽的访问属性对于connect/disconnect 无效 ,这一点有点破坏面向对象的封装性,但是却更有利于实际开发的工作。

信号与槽的意义:

-最大限度的弱化了类之间的耦合关系

-在设计阶段,可以减少不必要的接口类(抽象类)

-在开发阶段,对象间的交互通过信号与槽动态绑定

你可能感兴趣的:(#,QT深度剖析,qt,信号与槽函数)