信号与槽是一种高级接口,称为对象之间的通信,它是QT的核心特性(有点类似MFC的消息机制)。

信号

当QPushButton,在鼠标单击后发射clicked()时,某个信号指示客户或所有者发送其内部状态发生变化,信号将被一个对象发射。

  • 信号只声明不实现。
signals: 
void showDlg(); /*返回类型都是void*/

  • 信号可以通过关键字emit来发射



emit showDlg();

槽函数

插槽函数可以像普通的C ++成员函数一样,可以被正常调用,也可以与信号关联。当关联的信号被发射时,这个插槽函数就会被调用。

槽函数也存在权限:


  • public slots:任何对象都可将将信号与之相连接。
  • protected slots:当前类及其子类可以将信号与之相连接。
  • private slots:只有类自己可以将信号与之相连接。

信号与槽函数的连接

static QMetaObject::Connection connect(const QObject *sender,\
const char *signal,const QObject *receiver, \
const char *member, Qt::ConnectionType = Qt::AutoConnection);



  • 发件人:信号发射者对象
  • 信号:信号
  • 接收器:信号接收者
  • 成员:槽函数
  • ConnectionType:连接类型。默认自动连接

一个信号连接一个槽​ 

一个信号要和槽函数成功相连,他们的参数必须具有相同的顺序和相同的类型,或者允许信号的参数比槽函数多,槽会自动忽略掉多余的参数而进行调用

QObject::connect(btn, SIGNAL(clicked(bool)), this, \
SLOT(btnAddClicked()));

一个信号可以连接多个槽

使用QObject :: connect将一个信号连接到多个槽时,当信号发射时,将按声明联系时的顺序顺序调用

connect(A,SIGNAL(recvFinshed(const QList<QByteArray> &)), B , \
SLOT(onRecvFinsed(const QList<QByteArray> &)));
connect(A,SIGNAL(recvFinshed(const QList<QByteArray> &)), C ,\
SLOT(onRecvFinsed(const QList<QByteArray> &)));

多个信号连接同一个槽函数

当多个信号连接到同一个槽上时,每个信号的发送,都会调用这个槽。

connect(A,SIGNAL(recvFinshed(const QList<QByteArray> &)), C ,\
SLOT(onRecvFinsed(const QList<QByteArray> &)));
connect(B,SIGNAL(recvFinshed(const QList<QByteArray> &)), C , \
SLOT(onRecvFinsed(const QList<QByteArray> &)));

一个信号可以和另外一个信号连接​ 

当发射第一个信号时,也会把第二个信号发送出去

//两个信号相连
connect(&a,SIGNAL(valueChanged(QString)),&b,\
SIGNAL(valueChanged(QString)));
//再建立b与c的连接
connect(&b,SIGNAL(valueChanged(QString)),&c,\
SLOT(setValue(QString)));
//下面的操作同时发送了信号a.valueChanged与b.valueChanged
a.setValue("this is A");
//从而信号b.valueChanged被槽c.setValue所接收

连接可以被除去​ 

去除B与C之间的连接

disconnect(B,SIGNAL(recvFinshed(const QList<QByteArray> &)), C ,\
SLOT(onRecvFinsed(const QList<QByteArray> &)));

自定义信号

所有继承QObject或者它的子类都可以包含信号与槽,所以我们自定义的类一定要继承QObject(或者其子类)。所有包含信号与槽的类都必须声明Q_OBJECT宏

以下是简单的结构,代码细节暂时忽略。

......
class classname : public QObject
{
Q_OBJECT //必须包含
public:
classname ()
public slots:
void slotfunction();
signals:
void signalxxx();
}
......

总结


  • 信号与槽机制本身就是一种通信机制
  • 和MFC消息机制有相似地方
  • 槽函数本质上是一种回调函数。不过信号与槽可以一对多或者多对一,降低了对象的耦合度
  • 在看嵌入式中断回调机制,是不是也有相通的地方。不过中断涉及到操作系统调度,会抢占一些操作。