Qt 信号与槽
目录信号与槽的概念
Qt的信号与槽机制概述
信号和槽机制是Qt的核心特性,用于多个对象之间的通信。Qt的元对象(meta)机制是信号和槽实现的基础。
特点:
- 信号和槽机制是类型安全的:信号的参数必须与接收槽函数的参数相匹配。(实际上,槽的参数可以比它接收到的信号参数更少,因为槽可以忽略额外的参数)
- 信号和槽函数是松耦合的:当一个对象发出信号,该对象不知道也不关心哪个对象的槽函数会接收该信号。Qt的信号和槽函数机制确保:如果将一个信号连接到一个槽函数上,该槽函数将在正确的时间被调用。
- 可以将多个信号连接到一个槽函数上(即【多对一】),而一个信号也可以连接到多个槽函数上【即一对多】
信号函数
- 可以重载
- 定义在某个类中,该类直接或间接继承自
QObject
类,且添加Q_OBJECT
宏【激活元对象机制】 - 用
signals
关键字修饰; - 信号函数只需要声明,不需要定义(实现),实现是由QT的moc工具自动完成的;
- 信号函数的返回值类型必须为
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;
}
};
槽函数与信号函数的连接
1、使用Qt设计师
详见:Qt 默认静态槽函数 connectSlotsByName浅析 - 3的4次方 - 博客园 (cnblogs.com)
2、使用 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()
以及信号和槽声明宏。
在Qt4中,使用 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)第三种方法:使用函数指针。
在Qt5中,可以使用函数指针取代宏。
connect(sender, &QObject::destroyed, this, &MyObject::objectDestroyed);
-
优点:允许编译器检查信号的参数是否与槽的参数兼容。如果需要,编译器还可以隐式地转换参数
-
缺点:无法识别函数重载的情况
Qt预定义的信号与槽
在对应的控件的Qt助手文档中的 Signal Documentation 栏下面有罗列
标签:Qt,自定义,QObject,connect,信号,函数 From: https://www.cnblogs.com/3to4/p/17185458.html