QT窗口容器层层嵌套过于耦合的解决办法

  • Post author:
  • Post category:其他



目录


零、多层嵌套窗口使用信号槽通信遇到的问题


一、单例模式的消息中间类


1.创建消息中间类


transmitsignals.h内容如下:


transmitsignals.cpp内容如下:


2.在需要发信号的sender类中使用


3.需要接收信号的receiver类中使用


MainWindow::doProcessReceiveMsg槽函数:


4.点击按钮测试是否可行


5.使用消息中间类可能会遇到一些问题


6.其他方法


1.)观察者模式


2.)循环发送,定时接收的情况


零、多层嵌套窗口使用信号槽通信遇到的问题

稍微复杂点的项目可能就会遇到一个窗口套一个窗口的情况,两个窗口之间使用信号槽还是很方便的,一但嵌套的层数在三个以上,使用信号槽就有点麻烦,比如下图这种。


第一个窗口套第二个窗口,第二个窗口里面有第三个窗口,而有时候第三个窗口需要直接给第一个窗口发信息,但是第一个窗口没有关联第三个窗口,所以只能先向第二个窗口发信号,再由第二个窗口向第一个窗口发信号。

好像也不是太麻烦,但如果层次再深一点呢?五层、六层、七层…..如果还是层层传递信号,工作量增加不说,写出来的代码也不便阅读。

那么怎么解决这个问题?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等消息中间件可能是一个更好的选择。



版权声明:本文为youthshadows原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。