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

原创 2018年04月15日 10:13:36

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

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

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
  • 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
  • obesrverApater:该类的主要目的是attach的时候,将传进来的槽函数直接绑定到改类的notify信号,因为传进来的槽函数,要想在触发时去掉用拿不到函数名称,所以借助中间层直接绑定,在触发的时候直接去触发中间层的信号,就可达到目的。
  • obesrverApaterFactory:创建中间层的工厂,方便类创建。
  • -

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

  • 工厂类去创建中间层对象实体
obesrverApater *obesrverApaterFactory::createObesrverApater()
{
    return new obesrverApater();
}
  • 观察者绑定函数实现
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);
}

- 观察者解绑函数实现

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++;
    }
}
  • 观察者触发函数实现
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++;
    }
}
  • 程序结束时别忘了销毁
globalObserver::~globalObserver()
{
    //释放列表数据
    QList<relationData*>::iterator iter = m_oRelationList.begin();

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

}

测试:

  • 测试代码
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");
}

源码下载

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

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/q862343646/article/details/79947005

Qt基础与Qt on Android入门

本课程起始于基础的开发环境搭建和Qt Creator快速介绍,帮助初学者入门;着力于Qt的内在机制,由浅入深介绍信号与槽、Qt模板库、事件、文件处理、XML、网络、多线程、各种GUI控件、布局管理器等各种Qt基础主题(这些主题可同时在Qt桌面编程和Android平台上使用),同时辅以简洁有效有针对性的实例程序(每个示例程序都可以在 Android 平台上运行)。
  • 2014年11月27日 10:53

QT 窗体间通信

多窗体的实现我们可以在 1:在一个创体内控制另一个窗体显示(信号,槽的使用) 2:在一个窗体内触发另一个窗体内的信号,槽,函数 (信号,槽的使用) 3,在一个创体内修改另一个创体内部件的属性,值...
  • liang890319
  • liang890319
  • 2011-12-12 19:01:06
  • 9035

QT多窗口间传值---信号槽方法

在写程序时,难免会碰到多窗体之间进行传值的问题。依照自己的理解,我把多窗体传值的可以使用的方法归纳如下:       1.使用QT中的Signal&Slot机制进行传值;       2....
  • lywzgzl
  • lywzgzl
  • 2014-11-13 19:38:33
  • 6848

Qt主界面和一个新的Dialog的通信(交互)

1.需求 经常需要实现一个主界面弹出一个新的窗口输入内容后将一些信息再返回给主界面 2.方法 采用信号和槽的方式 3.主要代码代码 建立工程后会有一个MainWindow,在Form下新建一...
  • maowendi
  • maowendi
  • 2016-08-23 17:18:25
  • 5462

QT窗体间传值总结之Signal&Slot

在写程序时,难免会碰到多窗体之间进行传值的问题。依照自己的理解,我把多窗体传值的可以使用的方法归纳如下:       1.使用QT中的Signal&Slot机制进行传值;       2.使用全局...
  • hanxing0
  • hanxing0
  • 2013-06-13 16:18:25
  • 21023

Qt之进程间通信(QProcess)

简述QProcess可以在应用程序内部与其它进程通信,或启动其它应用程序。与在终端机之类的命令输入窗口上使用名称和参数是一样的,可以使用QProcess提供的函数start()启动进程。可以注册QSt...
  • u011012932
  • u011012932
  • 2016-01-28 18:44:20
  • 14297

Qt之进程间通信(Windows消息)

简述通过上一节的了解,我们可以看出进程通信的方式很多,今天分享下如何利用Windows消息机制来进行不同进程间的通信。简述 效果 发送消息 自定义类型与接收窗体 发送数据 接收消息 设置标题 重写na...
  • u011012932
  • u011012932
  • 2016-01-26 19:29:48
  • 8425

通过Windows<em>窗口</em>消息实现 <em>QT</em>进程<em>间通信</em>

被举报人: aisq2008 举报的资源分: 3 *类型: *详细原因: 取  消 提  交 通过Windows<em>窗口</em>消息实现 <em>QT</em>进程<em>间通信</em> 3积分 立即下载 ...
  • 2018年04月19日 00:00

QT父窗口和子窗口互相通信

这个问题上网查了好多,大神们都说的很简单,对于我这样的小白来说,理解起来就有点吃力了,下面记录一下,给自己留给笔记,也是给正在摸索中的小白们一点参考! 一  大家要明白如何建立子窗口:  ...
  • u011430225
  • u011430225
  • 2016-08-24 16:28:16
  • 2811

【<em>QT</em>】父组件与子组件的相互<em>通信</em>例子(用signal

【<em>QT</em>】父组件与子组件的相互<em>通信</em>例子(用signal-slot实现)目标: 新建一个QMainWindow<em>窗口</em>,在该<em>窗口</em>中添加一个打开按钮,一个spinBox,点击打开按钮后弹出一个对话框,...
  • 2018年04月16日 00:00
收藏助手
不良信息举报
您举报文章:Qt实现全局观察者模式(多层窗体之间直接传递消息)
举报原因:
原因补充:

(最多只允许输入30个字)