参考:【Qt】一篇全面的信号和槽函数机制总结_iriczhao的博客-CSDN博客_qt 信号和槽的机制
信号和槽机制是Qt的核心特性,用于多个对象之间的通信。Qt的元对象系统是信号和槽实现的基础。
特点:
QObject
类,且添加 Q_OBJECT
宏signals
关键字修饰;void
,参数的类型和个数不限。在Qt框架下,信号发出分为两种:
【每个类预定义的信号】:这些信号何时发出可以通过查看官方文档获知。
【自定义的信号】:这些信号的发出由开发人员自行定义。
在此讲解自定义信号。
示例:
class MyWidget:public QWidget{
//Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
Q_OBJECT
//信号函数
signals:
//自定义的信号函数
void MySignal(QString message);
};
信号可以从任何地方发出,但是建议:【只从定义该信号的类及其子类发出信号】
对于 Qt 提供给我们的信号函数,其底层已经设置好了信号发出的时机,例如按下鼠标时、点击 Enter 回车键时等等。
对于自定义的信号,我们需要自己指定信号发出的时机,需要使用 emit
关键字,专门用来发射信号。
可以在任何地方emit
发射信号,不一定要在信号函数的函数体内。
用法是在自定义信号函数的函数体内使用 emit
关键字发射信号,格式如下:
emit 自定义信号函数(自定义信号函数的实参列表);
示例:
class MyWidget:public QWidget{
//Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
Q_OBJECT
//信号函数
signals:
void MySignal(QString mess);
public:
void emitSignal(){
emit MySignal(message);//使用emit发射信号
}
private:
QString message;
};
注意:
emit
语句之后的代码将在所有槽函数都返回之后才执行。如果使用排队连接,情况略有不同,在这种情况下,emit
关键字后面的代码将立即继续,槽函数将稍后执行。
槽函数是普通的C++成员函数,当一个连接到槽函数的信号被发射时,槽函数将被调用;由于槽是普通的成员函数,所以它们在直接调用时遵循普通的C++规则。但是作为槽函数时,任何组件都可以通过信号连接从而调用它们。
slot
关键字声明槽函数,Qt5之后可以不用示例:
class MyWidget:public QWidget{
//Q_OBJECT 是一个宏,添加它才能正常使用 Qt 的信号和槽机制
Q_OBJECT
//信号函数
signals:
//自定义的信号函数
void MySignal(QString message);
//槽函数
public slots:
void recSlot2(QString mess1,QString mess2){
qDebug() << "执行 recSlot2() 槽函数,输出"<< mess1 << " " << mess2;
}
};
详见:Qt 默认静态槽函数 connectSlotsByName浅析_3的4次方的博客-CSDN博客
QObject::connect()
函数原型:
//connect(信号的发送者,信号的具体信息,信号的接受者,信号的处理[槽])
[static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
(1)第一种方法:使用QObject::connect()
以及信号和槽声明宏。
在Qt 4中,使用 SIGNAL()
宏声明信号,SLOT()
宏声明槽。
在SIGNAL()
和SLOT()
宏中包含参数的规则是:传递给SIGNAL()
宏的参数不能少于传递给SLOT()
宏的参数。
优点:信号和槽参数很直观
缺点:使用宏,编译时不做类型检查,只能在运行时发现错误
以下合法:
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*)));
(2)第二种方法:使用C++11的lambda函数
connect(sender, &QObject::destroyed, this, [=](){ this->m_objects.remove(sender); });
在这两种情况下,我们在connect()
调用中提供这个上下文。上下文对象提供关于应该在哪个线程中执行接收器的信息。
当发送方或上下文被销毁时,lambda将断开连接。注意:当信号发出时,函数内部使用的所有对象依然是激活的。
优点:代码简洁
(3)第三种方法:使用函数指针。
在Qt 5中,可以使用函数指针取代宏。
connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
优点:允许编译器检查信号的参数是否与槽的参数兼容。如果需要,编译器还可以隐式地转换参数
缺点:无法识别函数重载的情况
在对应的控件的Qt助手文档中的 Signal Documentation 栏下面有罗列