1、 Qt中信号(SIGNAL)的本质
1.1、 信号只是一个特殊的成员函数声明
1.1.1、 函数的返回值是void类型
1.1.2、 函数只能声明不能定义(实际上定义的部分是由moc自动生成的)
1.2、 信号必须使用signals关键字进行声明
1.2.1、 函数的访问属性自动被设置为protected(即#define signals public)
1.2.2、 只能通过emit关键字调用函数(发射信号)
2、 信号与槽的对应关系
2.1、信号与槽的对应关系
2.1.1、 一个信号可以连接到多个槽(一对多,如signal5对应slot2、slot3)
2.1.2、 多个信号可以连接到一个槽函数(多对一,如signal1、signal3对应slot1)
2.1.3、 一个信号可以连接到另一个信号(转嫁,如signal4触发signal6,slot4接收)
2.1.4、 连接可以被disconnect函数删除(移除,但一般不需要调用该函数,因为当一个对象被删除时,会自动断开与连接的信号或槽)
自定义槽函数
#ifndef _RXCLASS_H_
#define _RXCLASS_H_
#include <QObject>
#include <QDebug>
class RxClass : public QObject
{
Q_OBJECT
public:
protected slots:
void mySlot(int v) //自定义接受处理槽
{
qDebug() << "void mySlot(int v)";
//sender()为QObject类的protected成员函数
qDebug() << "Sender" << sender()->objectName();
qDebug() << "Receiver" << this->objectName();//接收处理对象name
qDebug() << "Value" << v;
qDebug() << endl;
}
};
#endif // RXCLASS_H
自定义信号
#ifndef _TESTSIGNAL_H_
#define _TESTSIGNAL_H_
#include <QObject>
class TestSignal : public QObject
{
Q_OBJECT //继承自QObject,使用信号槽机制,必须使用该宏。
public:
void send(int i)
{
emit testSignal(i);//发射信号
}
signals://默认protected的。
void testSignal(int v);
};
#endif // TESTSIGNAL_H
main.cpp
#include <QtCore/QCoreApplication>
#include <QDebug>
#include "TestSignal.h"
#include "RxClass.h"
void emit_signal()//发送信号到槽
{
qDebug() << "emit_signal()" << endl;
TestSignal t;
RxClass r;
t.setObjectName("t");
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_to_multi()
{
qDebug() << "one_to_multi()" << endl;
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)));
t.send(100);//发送一次相同的函数,两个接受者。
}
//多信号对一槽
void multi_to_one() //
{
qDebug() << "multi_to_one() " << endl;
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(101); //两个发送的信号被同一个槽接收。
t2.send(102);
}
//(转嫁:一个信号触发另一个信号)
void signal_signal()
{
qDebug() << "signal_signal() " << endl;
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(101); //有个间接多信号对一个槽的关系。
t2.send(102);
}
int main(int argc, char *argv[])
{
QCoreApplication a(argc, argv);
//emit_signal();
//one_to_multi();
//multi_to_one();
signal_signal();
return a.exec();
}
3、 不可忽视的军规
3.1、 Qt类只能在头文件中声明,不能放到cpp文件去声明
3.2、 信号与槽的原型应该完全相同
3.3、 信号参数多个槽参数时,多余的参数被忽略
3.4、 槽函数的返回值必须是void类型
3.5、 槽函数可以像普通成员函数一样被调用
3.6、 信号与槽的访问属性(譬如private,public)对于connect/disconnect无效
4、 信号与槽的意义
4.1、 最大限度的弱化了类之间的耦合关系
4.2、 在设计阶段,可以减少不必要的接口类(抽象类)
4.3、 在开发阶段,对象间的交互通过信号与槽动态绑定
5、小结
5.1、 信号只是一个特殊的成员函数声明
5.2、 信号必须使用signals关键字进行声明
5.3、 信号与槽可以存在多种对应关系
5.4、 信号与槽机制使得类间关系松散,提高类的可复用性。