(7条消息) Qt全局信号通信
应用场景分析
Qt开发中经常会遇到作用域跨度比较大的对象间通信的场景,如果直接使用信号槽通过对象指针直接连接,首先需要将对象指针互相暴露出来,其中可能涉及到各种复杂的传递过程,导致程序混乱。一种解决方案是建立全局的信号中转站,实现全局范围内的便捷通信。
功能实现1
设现有对象A,需要将信号signalA()发送给对象B。
- 建立单例类class SIgnalStation。
- 在单例类中定义中转信号void transSignalA()。
- 在A的代码中,将A的信号与信号中转的信号连接:
A:: connect(this, SIGNAL(signalA()), SIgnalStation::instance(), SIGNAL(transSignalA())); - 在对象B中连接中转信号:
B::connect(SignalStation::instance(), SIGNAL(transSignalA()), this, SLOT(…));
这样就实现了进程中任何对象间信号传递。
功能实现2
此种实现是用ID或字符串来实现对信号的索引,如下表所示:
信号标识 | 信号签名 |
---|---|
const char *MSG_ID_START = “MSG_ID_START”(任意可以标识的字符串) | void sigStart(char *info) |
const char *MSG_ID_END = “MSG_ID_END”(任意可以标识的字符串) | void sigEnd(char *info) |
… | … |
通过这样的映射,可以实现更低的耦合,映射由一个管理器管理,如GlobalMsgMgr类。此类提供两个接口:
addEmit(const char *msg_id(信号ID), const char *signal(信号签名)):用于将本地信号绑定到信号ID上,本地信号触发时,自动触发所有连接到此信号ID上的槽。
addSlot(const char *msg_id(信号ID), const char *slot(槽签名)):用于将本地槽绑定到信号ID上,任意信号触发源触发此信号时,本地槽会被调用。
综上,
实现2比实现1的耦合程度更低,单从ID上看不出信号参数类型;好处是可以通过ID实现更松的耦合,甚至可以实现信号ID的比较运算。
实现1、实现2在触发信号时稍微麻烦一点,因为触发信号时,需要定义本地的信号。
功能实现3
参考:Qt使用信号槽模拟全局广播
这种方式在发送信号时较为简单,但是在定义和编译时略复杂。
个人推荐使用功能实现2。
FAQ
为什么不用回调函数呢,因为信号槽可以很容易实现跨线程通信,回调函数跨线程调用需要处理竞争同步的问题。
未完待续
赞 (0)