Qt信号与槽
在 GUI 用户界面里,当用户对某个窗口部件进行操作时,往往需要其他窗口部件作出响应。传统做法通常借助 callback(回调机制)达成这一目的。回调机制是指预先把函数指针当作参数传递给另一个函数,随后在函数处理流程的恰当位置调用该回调函数。不过,回调机制存在两大明显缺陷:其一,类型不安全,无法确保在调用函数期间使用正确的参数;其二,强耦合,处理函数必须明确知晓要调用哪个回调函数。
与之相比,Qt 的信号与槽机制具备类型安全、松耦合的特点,使用起来更为灵活、便捷。信号与槽(Signal & Slot)不仅是 Qt 编程的基石,更是 Qt 的一项重大创新。得益于信号与槽这一编程机制,在 Qt 中处理界面各组件间的交互操作变得更加直观、简易。
1.信号
信号(Signal)本质上是在特定情形下被触发的事件。以 PushButton 为例,其最常见的信号便是在鼠标单击时发射的 clicked() 信号。在 Qt 里,发射信号需使用 emit 关键字。而 signals 关键字则用于标识进入信号声明区域,此后便可以声明自定义的信号。
定义信号,信号无需实现
signals:void A(QString & str); //信号不能也不需要实现
发射信号:
QString str = "迪迦好帅!"
emit A(str); //emit关键字发射信号
2.槽函数
槽(Slot)就是对信号响应的函数。槽就是一个函数,与一般的 C++函数是一样的,可以声明在类的任何部分(public、private 或 protected),可以具有任何参数,也可以被直接调用。槽函数与一般的函数不同的是:槽函数可以与一个信号关联,当信号被发射时,关联的槽函数被自动执行。
声明1个槽方法,如:
private slots:void printStr(QString & str);
槽方法的实现:
void MainWindow :: printStr(QString &str)
{qDebug()<<str;
}
3.信号与槽关联
GUI 程序设计的核心在于处理界面组件的信号响应,只要清楚何时发射何种信号,并合理地响应和处理这些信号就行。
信号与槽的连接实现
信号与槽的关联通过 `QObject::connect()` 函数达成,其原型如下:
QMetaObject::Connection QObject::connect(const QObject *sender, // 信号发送者const char *signal, // 发送的信号const QObject *receiver, // 信号接收者const char *method, // 与信号连接的方式,可为槽或信号Qt::ConnectionType type = Qt::AutoConnection // 连接方式,默认自动连接
);
常用格式为:`connect(sender, SIGNAL(signal()), receiver, SLOT(slot()));`。这里使用 `SIGNAL` 和 `SLOT` 两个宏来构造表示信号和槽的字符串,将函数原型用它们包裹起来。注意,使用这种方式时函数原型只能写类型,不能有参数名,否则连接会失败。
信号与槽的连接方式
1. Qt::AutoConnection:默认方式,由系统自动选择合适的连接方式。
2. Qt::DirectConnection:直接方式,信号发射时马上调用槽函数。
3. Qt::QueuedConnection:队列方式,信号发射后产生一个事件进入队列,事件被处理时才调用槽函数。
4. Qt::BlockQueuedConnection:阻塞队列方式,信号发射产生事件进入队列,当前线程会阻塞,直到事件处理完。若接收方和发送方在同一线程,程序会出现死锁,所以该方式仅用于多线程。
信号与槽的参数及其他注意事项
信号:可看作特殊函数,要带括号,能有参数,无需也不能实现。
槽函数:要带括号,有参数时需指明参数类型。
参数匹配:在 `connect()` 函数里写明参数类型,信号参数要和槽参数列表一致,允许信号参数比槽参数多。若不匹配或参数过少,会导致编译或运行错误。
Q_OBJECT宏:使用信号与槽的类,其定义中必须加入 `Q_OBJECT` 宏。
执行顺序:信号发射时,关联的槽函数通常立即执行,如同正常调用函数。只有所有关联槽函数执行完,才会执行发射信号处后面的代码。
信号与槽关联特点
1 一个信号连接一个槽:
connect(sender, SIGNAL(single1()), receiver, SLOT(slotFun()));
2 一个信号连接一个信号:
connect(sender, SIGNAL(single1()), receiver, SIGNAL(single2()));
3 一个信号连接多个槽,关联信号的槽函数按照建立连接时的顺序依次执行:
connect(sender, SIGNAL(single1()), receiver1, SLOT(slotFun()));
connect(sender, SIGNAL(single1()), receiver2, SLOT(slotFun()));
connect(sender, SIGNAL(single1()), receiver3, SLOT(slotFun()));
4 多个信号连接一个槽:
connect(sender1, SIGNAL(single1()), receiver, SLOT(slotFun()));
connect(sender2, SIGNAL(single2()), receiver, SLOT(slotFun()));
connect(sender3, SIGNAL(single3()), receiver, SLOT(slotFun()));
5 信号与槽的自动关联:
ui_xxxx.h 文件中 connectSlotsByName()方法通过对象名支持信号与槽的自动关联。不采用 connect()函数而是采用 on_objectName_signal 命名方式命名槽达到自动关联的效果。