slimfeng / QT / Qt实现全局观察者模式(多层窗体之间直接...

分享

   

Qt实现全局观察者模式(多层窗体之间直接传递消息)

2019-02-12  slimfeng
近来做项目发现,多个窗体之间要通信真的好麻烦,比如:A调出B,B调出C,那么C给A发消息,那就得经过B转发才能实现。对于两三层窗体,这种方法还可以接受,但嵌套太多就有点烦人了。
基于这个原因,那么要实现的东西就很清楚了,有一个全局类,去直接绑定信号槽关系,在需要触发的时候,通过这个全局类的函数,去相应的触发一下,就可以实现直连通信了。
  • 1
  • 2

globalObserver.h

#ifndef GLOBALOBSERVER_H
#define GLOBALOBSERVER_H

#include <QObject>
#include "obesrverApater.h"

struct relationData
{
    QString type;
    QObject *reciver;
    obesrverApater *obesrverApater;
};

class globalObserver : public QObject
{
    Q_OBJECT
public:
    //因为是全局只有一个,所以直接单例模式
    static globalObserver* getGlobalObserver();
    static void release();
    static globalObserver *m_pInst;
    //绑定
    void attach(const QString type, QObject *reciver, const char *method);
    //解绑
    void detach(const QString type, const QObject* reciver);
    //触发
    void notify(const QString type);
private:
    explicit globalObserver(QObject *parent = 0);
    ~globalObserver();

private:
    QList<relationData*> m_oRelationList;
};

#endif // GLOBALOBSERVER_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • relationData:结构体,保存对应关系;
  • relationData::type:字符串类型,就相当于信号的唯一标识符
  • relationData::reciver:信号接收者,保存这个变量主要实在detach的时候去使用。
  • relationData::obesrverApater;这个类的作用就很重要了,具体看该类的详解。

obesrverApater.h

#ifndef OBESRVERAPATER_H
#define OBESRVERAPATER_H

#include <QObject>
class obesrverApater;

//工厂,方便构造对象
class obesrverApaterFactory
{
public:
    static obesrverApaterFactory *getInst();
    static void realese();
    static obesrverApaterFactory* inst;

    obesrverApater* createObesrverApater();

private:
    obesrverApaterFactory()
    {}
};

//中间层,用来连接信号槽
class obesrverApater : public QObject
{
    Q_OBJECT
public:
    explicit obesrverApater(QObject *parent = 0);

signals:
    void notify();
};

#endif // OBESRVERAPATER_H
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • obesrverApater:该类的主要目的是attach的时候,将传进来的槽函数直接绑定到改类的notify信号,因为传进来的槽函数,要想在触发时去掉用拿不到函数名称,所以借助中间层直接绑定,在触发的时候直接去触发中间层的信号,就可达到目的。
  • obesrverApaterFactory:创建中间层的工厂,方便类创建。
  • -

接下来就主要看看具体函数的实现了:

  • 工厂类去创建中间层对象实体
obesrverApater *obesrverApaterFactory::createObesrverApater()
{
    return new obesrverApater();
}
  • 1
  • 2
  • 3
  • 4
  • 观察者绑定函数实现
void globalObserver::attach(const QString type, QObject *reciver, const char *method)
{
    obesrverApater *oA = obesrverApaterFactory::getInst()->createObesrverApater();
    connect(oA, SIGNAL(notify()), reciver, method);
    relationData *data = new relationData();
    data->type = type;
    data->reciver = reciver;
    data->obesrverApater = oA;
    m_oRelationList.append(data);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

- 观察者解绑函数实现

void globalObserver::detach(const QString type, const QObject *reciver)
{
    QList<relationData*>::iterator iter = m_oRelationList.begin();

    while (iter != m_oRelationList.end())
    {
        if ((*iter)->type.compare(type) == 0 && (*iter)->reciver == reciver)
        {
            relationData *data = *iter;
            m_oRelationList.removeOne((*iter));

            delete data->obesrverApater;
            delete data;
            return;
        }
        iter++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 观察者触发函数实现
void globalObserver::notify(const QString type)
{
    QList<relationData*>::iterator iter = m_oRelationList.begin();
    while (iter != m_oRelationList.end())
    {
        if ((*iter)->type.compare(type) == 0)
        {
            emit (*iter)->obesrverApater->notify();
        }
        iter++;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 程序结束时别忘了销毁
globalObserver::~globalObserver()
{
    //释放列表数据
    QList<relationData*>::iterator iter = m_oRelationList.begin();

    while (iter != m_oRelationList.end())
    {
        delete (*iter)->obesrverApater;
        delete *iter;
        iter++;
    }

}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

测试:

  • 测试代码
Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    globalObserver::getGlobalObserver()->attach("haha", this, SLOT(haha()));
    globalObserver::getGlobalObserver()->attach("hehe", this, SLOT(hehe()));

    QPushButton *p = new QPushButton("haha", this);
    connect(p, SIGNAL(clicked()), this, SLOT(onHaha()));
    p->setGeometry(10, 10, 200, 40);
}

Widget::~Widget()
{
    globalObserver::getGlobalObserver()->detach("haha", this);
    globalObserver::getGlobalObserver()->detach("hehe", this);
}

void Widget::haha()
{
    QMessageBox::about(this, "", "haha");

}

void Widget::hehe()
{
    QMessageBox::about(this, "", "hehe");
}

void Widget::onHaha()
{
    globalObserver::getGlobalObserver()->notify("haha");
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

源码下载

备注:自己在空闲时间写的,功能相对简单,有问题欢迎讨论!

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。

    来自: slimfeng > 《QT》

    0条评论

    发表

    请遵守用户 评论公约

    类似文章
    喜欢该文的人也喜欢 更多

    ×
    ×

    ¥.00

    微信或支付宝扫码支付:

    开通即同意《个图VIP服务协议》

    全部>>