Qt中的核心机制--信号与槽
Qt中的核心机制—信号与槽
一、信号与槽介绍
**信号(Signal)😗*就是特定情况下被发射的事件。
**槽(Slot)😗*就是对信号响应的函数。
信号与槽进行关联是用QObject::connect()函数实现的,其基本格式是:
QObject::connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));
connect()函数是QObject类的一个静态函数,而QObject是Qt所有类的基类。
QObject::connect()函数有多种参数形式,在QtCreator中的源码声明如下:
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
inline QMetaObject::Connection connect(const QObject *sender, const char *signal,
const char *member, Qt::ConnectionType type = Qt::AutoConnection) const;
二、connect()函数的不同参数形式说明:
1.一种参数形式的原型是:
static QMetaObject::Connection connect(const QObject *sender, const char *signal,
const QObject *receiver, const char *member, Qt::ConnectionType = Qt::AutoConnection);
使用这种参数形式的connect()进行信号与槽函数连接时,一般的句法是:
QObject::connect(sender,SIGNAL(signal()),receiver,SLOT(slot()));
其中sender是发射信号的对象,signal()是信号名称,可以看作是特殊的函数,需要带括号,有参数时还需要指明参数。receiver是接受信号的对象,slot()是槽函数名称,需要带括号,有参数时还需要指明参数。
SIGNAL和SLOT是Qt的宏,用于指明信号和槽,并将他们的参数转换为相应的字符串。
就比如如下代码:
QObject::connect(btnClose,SIGNAL(clicked()),this,SLOT(close()));
其中btnClose是Qpushbutton 按钮对象,clicked()是QPushbutton()的点击信号,this是当前QWidget窗体,close()是当前QWidget窗体的槽函数。这样btnClose按钮就和 当前QWidget窗体的close()关联了。
2.另外一种参数形式的connect()函数原型是:
static QMetaObject::Connection connect(const QObject *sender, const QMetaMethod &signal,
const QObject *receiver, const QMetaMethod &method,
Qt::ConnectionType type = Qt::AutoConnection);
对于具有默认参数的信号与槽(即信号名称是唯一的,没有参数不同而同名的两个信号),可以使用函数指针的形式进行关联。
QObject::connect(btnClose,&QPushButton::clicked,this,&QWidget::close);
这种形式在参数比较多时,更加简便一些。
注意:对于同名但是有不同参数的信号不能采用函数指针的方式进行关联。
3.Qt::ConnectionType type = Qt::AutoConnection 参数说明:
不管是何种形式的connect()函数,最后都有一个Qt::ConnectionType类型的参数,默认值是:Qt::AutoConnection;
Qt::ConnectionType是枚举类型,表示信号与槽之间的关联方式,有以下几种取值方式:
Qt::AutoConnection(默认值):如果信号的发射者和接收者都在同一线程中,就使用Qt::DirectConnection方式,否则就使用Qt::QueuedConnection方式,在信号发射时自动确定关联方式。
Qt::DirectConnection:信号被发射时槽函数立即执行,槽函数与信号在同一个线程。
Qt::QueuedConnection:在事件循环回到接收者线程后执行槽函数,槽函数与信号在不同的线程。
Qt::BlockingQueuedConnect:与Qt::QueuedConnection,只是信号线程会阻塞直到槽函数执行完毕,当信号与槽函数在同一个线程时绝对不能使用这种方式,否则会造成死锁。
4.自定义信号及其使用:
在类中可以自己定义信号,信号就是在类定义里声明一个函数,但是这个函数无需实现,只需发射(emit)。
例如:
自定义信号使用emit发射:
emit valueChange(); // 发射信号
三、关于信号与槽的使用有一些规则:
(1)一个信号可以连接多个槽。
QObject::connect(spinNum,SIGNAL(valueChangeed()),this,SLOT(Func1()));
QObject::connect(spinNum,SIGNAL(valueChangeed()),this,SLOT(Func2()));
当QSpinBox类型的对象spinNum,数值发生改变时,Func1和Func2都会响应。
当一个信号与多个槽函数关联时,槽函数按照建立的顺序依次执行。
当信号与槽函数带有参数时,在connect()函数里要写明参数的类型,但可以不写参数的名称。
(2)多个信号可以连接同一个槽。
(3)一个信号可以连接另外一个信号。
QObject::connect(spinNum,SIGNAL(valueChangeed()),this,SIGNAL(valueChanged());
这样当一个信号发射时,也发射另一个信号,实现某些特殊功能。
(4)一般情况下,信号与槽的参数个数应该一致,至少信号的中的个数不能少于槽函数中参数的个数。如果不匹配,会出现编译错误或者运行错误。
(5)在使用信号与槽的类中,必须在来的定义中加入宏Q_OBJECT。
(6)当一个信号被发射时,与其关联的槽函数通常被立即执行。只有当信号关联的槽函数执行完毕后,才会执行发射信号处后面的代码。
好了关于信号与槽的介绍就到这里了。以上说明均来自《Qt 5.9 C++ 开发指南》一书,更多的细节大家可以参考该书。