signal&slot - Qt的交互响应机制
Qt的信号和槽机制,不同于传统的callback机制,signal&slot机制,使得信号的触发与处理变得更加灵活且安全。
signal&slot - Qt的交互响应机制
1 原理
1.1 传统的callback机制
传统的callback是事件触发后,就去调用被触发对象的callback函数。
例如,一个Button被按下后,该Button的回调函数(callback function)就会被调用执行。
Matlab的GUI编程下通过编写callback函数,Java环境下通过设置事件监听函数。其实都是去重载原本默认为空的事件处理函数。
1.2 Qt的signal与slot机制
Qt采用 信号(signal) 与 槽(slot) 的机制来实现交互响应。
信号(signal) 与 槽(slot) 都是Qt中一个类的成员函数。
首先,信号需要和接收槽相连接。运行时,被触发的对象会释放(emit)信号,如果此信号有已连接的接收槽,那么该接收槽就会收到信号,以及其附带的参数,并进行事件处理。
2 connect
2.1 函数原型
1 | connect(sender, SIGNAL(signal), receiver, SLOT(slot)); |
- sender 是信号发送对象的指针
- signal 是信号发送对象的signal函数
- 例如,PushButton:
- 按下时,会释放pressed()的信号;
- 抬起时,会释放released()的信号;
- 单击时,会释放clicked()的信号;
- ……
- 例如,PushButton:
- receiver 是接收槽对象的指针
- slot 是接收槽对象的slot函数
- 此函数用于处理接收到signal函数信号之后,需要执行的内容
- 另外,SIGNAL 和 SLOT 都是Qt定义的宏函数,用于实现参数转换。
2.2 示例
1 | MainWindow::MainWindow(QWidget *parent) : |
此处,我在MainWindow的构造函数(construct func) 中,使用了connect函数来实现用户列表组件的点击信号与点击处理槽函数的连接。
- 当用户列表组件(ListWidget) 中的一个项目被单击后,就是释放出
itemClicked(QListWidgetItem*)
信号,这个信号会导致相连接的接收槽函数onUserClicked(QListWidgetItem*)
被调用。前者的参数QListWidgetItem*
会被传递给后者。
- 当用户列表组件(ListWidget) 中的一个项目被单击后,就是释放出
MainWindow的ui对象在拷贝构造函数开始执行之前已经构造生成。(C++冒号语法,不再赘述)
通过ui对象指针,可以获取当前的界面组件。
接收槽函数——
onUserClicked(QListWidgetItem*)
在接受类中先声明,再实现。声明:
```c++ class **** { ****
public slots: void onUserClicked(QListWidgetItem*);
}
1
2
3
4
5
6
7
8
9
10
- 实现:
- ```c++
void MainWindow::onUserClicked(QListWidgetItem *item)
{
QString currentUser = item->text();
****
}
2.3 进一步理解connect
signal和slot之间的关系没有限制,可以一对多,多对一;
1
2connect(sender, SIGNAL(signal), receiverA, SLOT(slotA));
connect(sender, SIGNAL(signal), receiverB, SLOT(slotB));- 一对多
1
2connect(senderA, SIGNAL(signalA), receiver, SLOT(slot));
connect(senderB, SIGNAL(signalB), receiver, SLOT(slot));- 多对一
signal和signal之间也可以互相连接,由一个signal的释放,触发后一个signal的释放。
1
2connect(sender, SIGNAL(signal), receiverA, SLOT(slotA));
connect(sender, SIGNAL(signal), receiverB, SLOT(slotB));- 一对多
连接关系可以动态连接,也可以动态断开
1
2connect(sender, SIGNAL(signal), receiver, SLOT(slot)); // 动态连接
disconnect(sender, SIGNAL(signal), receiver, SLOT(slot)); // 动态断开连接- 通过disconnect函数即可断开信号与槽的连接关系
3 进一步理解
3.1 自定义Qt类
尝试编写包含signal和slot的Qt类模型:
以下代码来源《Qt C++跨平台图形界面程序设计基础》 殷立峰 主编 清华大学出版社 245页。
(有改动)
1 | class Circle:Public QObject |
- 自定义的Circle类继承自QObject;
- 对外提供slots函数
setRadius,此函数用于设置圆形的新半径。
- 例如,可以根据用户的操作,触发setRadius函数,判断是否有变化后,更新圆形半径。
- 此函数特点在于,圆形半径更新后,它又释放出了一个信号——
emit radiusChanged(circleRadius);
。此信号函数也在Circle类中定义,是Circle类的信号函数。此信号函数携带着参数,会触发开发者编程时连接的槽函数,并将参数对应地传递给槽函数。实际编程中,槽函数例如:界面绘制刷新函数。这样就可以实现数据结构更新时的界面更新重绘。不需要盲目地轮询式查询数据结构,实时重绘显示。
3.2 总结
Qt的信号和槽机制,使得信号触发与信号处理的关系变得灵活且安全。
- 安全:各个封装好的组件与组件之间可以定向联系,而不打破封装性,不需要互访数据结构。
- 灵活:connect和disconnect可以动态执行,灵活地实现signal到slot,也即不同对象之间的函数到函数的动态连接和断开。