信号和槽机制是Qt的核心机制,可以让编程人员将互不相关的对象绑定在一起,实现对象之间的通信。
声明了信号的对象,当其状态改变时,信号就由该对象发送出去,而且该对象只负责发送信号,它不知道另一端是谁在接收这个信号。
槽用于接收和处理信号,一个槽并不知道是否有任何信号与自己相连接。
槽实际上只是普通的对象成员函数。当一个信号被发射时,与其相关的槽将被立即执行,就像一个正常的函数调用一样。
信号与槽机制完全独立于任何GUI事件循环。
信号
①信号(signal)的声明是在一个类的头文件中进行的
②Qt的signal关键字指出进入了信号声明区,随后即可声明自己的信号
例如:
signals:void stateChanged(int nNewVal); //定义信号
这里signals是Qt的关键字,而非C++的关键字。
信号函数stateChanged定义了信号stateChanged,这个信号带有参数nNewVal
信号函数语法受到以下几点约束:
①函数返回值是void类型,因为触发信号函数的目的是执行与其绑定的槽函数,无须信号函数返回任何值。
②开发人员只能声明而不能实现信号函数。
③信号函数被moc自动设置为protected,因而只有包含一个信号函数的那个类及其派生类才能使用该信号函数。
④信号函数的参数个数、类型由开发人员自行设定。这些参数的职责是封装类的状态信息,并将这些信息传递给槽函数。
⑤只有QObject及其派生类才可以声明信号函数
槽
①槽函数和普通的C++成员函数一样,可以被正常调用。
②槽唯一的特殊性就是很多信息可以与其相关联。
③当与其关联的信号被发送时,这个槽就会被调用。
④槽可以有参数,但槽的参数不能有默认值。关键字slots表名进入了槽函数声明区。
槽的声明也是在头文件中进行的,例如:
public slots: //此语句说明后面就是槽函数void Function(int nNewVal){qDebug() << "new Values" << nNewVal; //显示变量 }
槽函数的返回值是void类型,因为信号和槽机制是单向的:信号被发送后,与其绑定的槽函数会被执行,但不要求槽函数返回任何执行结果。和信号函数一样,只有QObject及其派生类才可以定义槽函数。
既然槽函数是普通的成员函数,因此与其他的函数一样,它们也有存取权限(public,protected,private)。也就是说,人们能控制其他类能够以怎样的方式调用一个函数。
关联信号与槽
通过调用QObject::connect函数可以绑定一个信号函数和一个槽函数,该函数最常用的格式如下:
connect(sender,SIGNAL(signal_func()),receiver,SLOT(slot_func()))
其中sender及receiver都是指向QObject(或其子类)对象的指针
前者指向发送信号的对象,后者指向处理信号的对象,两者分别被称为“发送者”及“接收者”。
signal_func以及slot_func分别是这两个对象中定义的信号函数和槽函数。
当指定信号signal时一般使用Qt的宏SIGNAL,指定槽函数时必须使用宏SLOT。
一个信号函数可以和多个槽函数绑定。
多个信号函数可以和一个槽函数绑定。
使用信号和槽机制时应该注意以下几点:
①信号和槽机制与普通函数调用一样,如果使用不当,在程序执行时也有可能产生死循环
②如果一个信号与多个槽相联系,那么当这个信号被发送时,与之相关的槽被激活的顺序将是随机的
③宏定义不能用在信号和槽的参数中。
④信号和槽的参数个数与类型必须一致
信号和槽举例
再次建立头文件
exampleA.h,修改其内容为
#ifndef EXAMPLEA_H
#define EXAMPLEA_H
#include<QCoreApplication>
class CExampleA:public QObject
{Q_OBJECTint m_Value;// 定义私有成员
public:CExampleA(){m_Value = 0;}void SetValue(int nNewVal){if (m_Value == nNewVal){ return ; }m_Value = nNewVal;// emit函数用来激活信号函数,发送信号emit stateChanged(m_Value);}
signals: // 定义信号函数,带参数void stateChanged(int nNewVal);
};
#endif // EXAMPLEA_H
exampleB.h,修改其内容为
#ifndef EXAMPLEB_H
#define EXAMPLEB_H
#include<QDebug> //包含调式类
#include<QCoreApplication>
class CExampleB:public QObject
{Q_OBJECT
public:CExampleB(){}
public slots: //定义槽函数void Function(int nNewVal) //nNewVal为100{qDebug() << "new Values" << nNewVal;}
};#endif // EXAMPLEB_H
再次打开新建对话框,添加主函数文件
main.cpp中修改为
#include<exampleA.h>
#include<exampleB.h>
int main()
{CExampleA a; //创建CExampleA类的对象a,调用构造函数,m_Value = 0CExampleB b; //创建CExampleB类的对象b//连接信号和槽,connect函数要求发送对象和接收对象均为指针,a,b是对象名,&a,&b是发送对象的指针和接收对象的指针。QObject::connect(&a,SIGNAL(stateChanged(int)),&b,SLOT(Function(int)));a.SetValue(100); //调用a对象的公有函数return 0;
}
运行
简单实现了信号与槽的功能