目录
MainWindow::doProcessReceiveMsg槽函数:
零、多层嵌套窗口使用信号槽通信遇到的问题
稍微复杂点的项目可能就会遇到一个窗口套一个窗口的情况,两个窗口之间使用信号槽还是很方便的,一但嵌套的层数在三个以上,使用信号槽就有点麻烦,比如下图这种。
第一个窗口套第二个窗口,第二个窗口里面有第三个窗口,而有时候第三个窗口需要直接给第一个窗口发信息,但是第一个窗口没有关联第三个窗口,所以只能先向第二个窗口发信号,再由第二个窗口向第一个窗口发信号。
好像也不是太麻烦,但如果层次再深一点呢?五层、六层、七层…..如果还是层层传递信号,工作量增加不说,写出来的代码也不便阅读。
那么怎么解决这个问题?QT是否有提供轮子?QT的事件机制似乎全局都可以接收,那么是否可以用自定义事件来解决?答案是否定的。
QEvent或者自定义Event需要指定*receiver才能发送,然后在receiver中通过event()或者customEvent()方法接收,这其实已经跟信号槽很相似了。
是否还有别的办法?答案是有的。
一、单例模式的消息中间类
第一种办法是创建并使用单例模式的消息中间类,直接由消息中间类发信号,接收的窗口类绑定这个信号,并实现槽函数。
1.创建消息中间类
transmitsignals.h内容如下:
#ifndef TRANSMITSIGNALS_H
#define TRANSMITSIGNALS_H
#include <QObject>
class TransmitSignals : public QObject
{
Q_OBJECT
public:
static TransmitSignals &GetInstance();
private:
TransmitSignals();
~TransmitSignals();
TransmitSignals(const TransmitSignals &) = delete;
TransmitSignals(const TransmitSignals &&) = delete;
TransmitSignals &operator=(const TransmitSignals &) = delete;
signals:
void SignalSendMsg(const QString msg);
void SignalSendFlag(const bool ret);
public slots:
};
#endif // TRANSMITSIGNALS_H
transmitsignals.cpp内容如下:
#include "transmitsignals.h"
TransmitSignals::TransmitSignals( )
{
}
TransmitSignals::~TransmitSignals( )
{
}
TransmitSignals& TransmitSignals::GetInstance()
{
static TransmitSignals RobotControl;
return RobotControl;
}
2.在需要发信号的sender类中使用
connect(m_sendBtn, &QPushButton::clicked, this, [&]{ TransmitSignals::GetInstance().SignalSendFlag(true); });
3.需要接收信号的receiver类中使用
connect(&TransmitSignals::GetInstance(), &TransmitSignals::SignalSendFlag, this, &MainWindow::doProcessReceiveMsg );
MainWindow::doProcessReceiveMsg槽函数:
void MainWindow::doProcessReceiveMsg(bool)
{
QMessageBox::information(this, "msg", "接收到了!");
}
实现很简单,只是在接收到后打印信息。
4.点击按钮测试是否可行
从测试结果来说是可行的。
5.使用消息中间类可能会遇到一些问题
比如可能有很多的信号,都放在一个类可能会很臃肿,比如多个类的信号集中在一个类中发送,可能会给阅读代码带来不便。这时或许应该按模块来构造消息中间类。
6.其他方法
1.)观察者模式
参考
Qt实现全局观察者模式(多层窗体之间直接传递消息)-支持传参
大佬的方法测试了一下,发现如果想要传参,需要根据参数的个数和类型写匹配规则,工作量巨大,最终放弃。
2.)循环发送,定时接收的情况
这样一个场景,多个发送者,每个发送者是一个定时器,一秒发送一次数据,让接收者更新界面,这时如果选择信号槽可能会降低系统效率,使用数据库的写入和读取、redis、RabbitMQ等消息中间件可能是一个更好的选择。