No.55~57 模型视图设计模式

模型试图设计模式的核心思想:

1、模型(数据)与视图(显示)相分离;

2、模型对外提供标准接口存取数据(不关系数据如何显示);

3、视图自定义数据的显示方式(不关系数据如何被组织和存储)。

直观理解:


其中Model指的就是 组织数据的方式

工作机制:

一、当数据发生改变时,模型发生信号通知视图,视图对数据的变化做出相应的调整。(自由解析)

二、当用户与视图进行交互时,视图发出信号,通过模型提取相应的数据。

Qt中的模型层次结构:


Qt中的视图层次结构:


问题1:模型如何为数据提供统一的访问方式?

    QFileSystemModel m_fsModel;  //定义模型:文件系统
    QTreeView m_treeView;//定义视图:树形

    m_treeView.setParent(this);
    m_treeView.move(10, 10);
    m_treeView.resize(500, 300);

    m_fsModel.setRootPath(QDir::currentPath());  //从当前工作目录中取数据:地址

    m_treeView.setModel(&m_fsModel);//连接模型与视图

    //设置为树形视图的数据索引,并从根部开始显示path中的内容
    m_treeView.setRootIndex(m_fsModel.index(QDir::currentPath()));

敲黑板:

在Qt中,不管模型以什么结构组织数据,都必须为每一个数据提供独一无二的索引,而视图就通过索引来对数据进行访问。



模型视图设计模式要点:

模型通过定义标准接口(成员函数)来对数据进行访问;

视图通过标准接口获取数据并定义显示方式;

模型使用信号与槽机制通知视图数据变化;

模型中的数据都是以层次机构表示的。

模型中的索引:

模型索引是数据与视图分离的重要机制;

模型中的数据使用唯一的索引来访问;

QModelIndex是Qt中的模型索引类,包括:

    1、具体数据的访问途径;

    2、一个指向模型的指针。

索引的意义:



注:特殊的模型可以自定义特殊的索引方式

索引的表示方法:

1、行和列:(row, column)   缺点:对树形结构的数据无法适用

2、通用树结构:


3、三元组:


注意:当父结点为虚拟root节点时,可以使用空索引(直接调用QModelIndex()产生)作为父节点参数。

.h文件如下:

#include <QWidget>
#include <QPlainTextEdit>
#include <QFileSystemModel>

class Widget : public QWidget
{
    Q_OBJECT

    QPlainTextEdit m_edit;
    QFileSystemModel m_fsModel;
protected slots:
    void onDirectoryLoaded(const QString& path);
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

实现文件如下:

#include "Widget.h"
#include <QDir>
#include <QModelIndex>
#include <QByteArray>
#include <QBuffer>
#include <QTextStream>

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_edit.setParent(this);
    m_edit.move(10, 10);
    m_edit.resize(500, 300);

    connect(&m_fsModel, SIGNAL(directoryLoaded(QString)), this, SLOT(onDirectoryLoaded(QString)));

    m_fsModel.setRootPath(QDir::currentPath());
}

void Widget::onDirectoryLoaded(const QString& path)
{
    QModelIndex root = m_fsModel.index(path);

    QByteArray array;
    QBuffer buffer(&array);

    if( buffer.open(QIODevice::WriteOnly) )
    {
        QTextStream out(&buffer);

        out << m_fsModel.isDir(root) << endl;
        out << m_fsModel.data(root).toString() << endl;
        out << root.data().toString() << endl;
        out << &m_fsModel << endl;
        out << root.model() << endl;
        out << m_fsModel.filePath(root) << endl;
        out << m_fsModel.fileName(root) << endl;
        out << endl;

        for(int i=0; i<m_fsModel.rowCount(root); i++)
        {
            QModelIndex ci = m_fsModel.index(i, 0, root);
            QModelIndex cj = m_fsModel.index(i, 1, root);
            QModelIndex ck = m_fsModel.index(i, 2, root);
            QModelIndex cl = m_fsModel.index(i, 3, root);

            out << ci.data().toString() << "   "<< cj.data().toString() << "   "<< ck.data().toString() << "   "<< cl.data().toString() <<endl;
        }

        out.flush();
        buffer.close();
    }

    if( buffer.open(QIODevice::ReadOnly) )
    {
        QTextStream in(&buffer);

        m_edit.insertPlainText(in.readAll());

        buffer.close();
    }
}

Widget::~Widget()
{

}

实现效果:



问题2:不同的视图如何显示同一个模型中的数据?有何特点?

问题效果如下:


如果按照上述方式进行数据组织,那么会导致一部分数据无法正常在视图中显示出来。

引入数据角色的概念:

1、模型中的数据在视图中的用途(显示方式)可能是不同的;

2、模型必须为数据设置特定的数据角色(数据属性);

3、数据角色用于确定不同数据在视图中的显示方式;

4、数据角色广义上指的是不同视图以同一风格显示数据的标准。

Qt中的数据角色定义:


数据角色的意义:

1、定义了数据在特定系统下的标准用途;

2、不同的视图可以以相同标准显示数据。

注:数据角色只是一个附加的属性,代表推荐的数据显示方式。

划重点:::

        不同视图完全可以自由解析或者忽略数据的角色信息。

编程表示:

.h文件如下:

#include <QWidget>
#include <QTableView>
#include <QStandardItemModel>
#include <QListView>
#include <QTreeView>

class Widget : public QWidget
{
    Q_OBJECT

    QStandardItemModel m_model;
    QTableView m_tableView;
    QTreeView m_treeView;
    QListView m_listView;

    void initModel();
    void initView();
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

实现文件:

#include "Widget.h"
#include <QStandardItem>

Widget::Widget(QWidget *parent)
    : QWidget(parent, Qt::WindowContextHelpButtonHint)
{
    initModel();
    initView();

    m_tableView.setModel(&m_model);
    m_listView.setModel(&m_model);
    m_treeView.setModel(&m_model);
}

void Widget::initModel()
{
    QStandardItem* root = m_model.invisibleRootItem();
    QStandardItem* itemA = new QStandardItem();
    QStandardItem* itemB = new QStandardItem();
    QStandardItem* itemC = new QStandardItem();

    QStandardItem* itemChild = new QStandardItem();

    itemA->setData("A", Qt::DisplayRole);
    itemA->setData("Tip A", Qt::ToolTipRole);
    itemA->setData("Help A", Qt::WhatsThisRole);

    itemB->setData("B", Qt::DisplayRole);
    itemB->setData("Tip B", Qt::ToolTipRole);
    //itemB->setData("Help B", Qt::WhatsThisRole);

    itemC->setData("C", Qt::DisplayRole);
    itemC->setData("Tip C", Qt::ToolTipRole);
    itemC->setData("Help C", Qt::WhatsThisRole);

    itemChild->setData("Child", Qt::DisplayRole);
    itemChild->setData("Tip Child", Qt::ToolTipRole);
    itemChild->setData("Help Child", Qt::WhatsThisRole);

    itemC->setChild(0, 0, itemChild);

    root->setChild(0, 0, itemA);
    root->setChild(0, 1, itemB);
    root->setChild(1, 0, itemC);
}

void Widget::initView()
{
   m_tableView.setParent(this);
   m_tableView.move(10, 10);
   m_tableView.resize(300, 100);

   m_listView.setParent(this);
   m_listView.move(10, 120);
   m_listView.resize(300, 100);

   m_treeView.setParent(this);
   m_treeView.move(10, 230);
   m_treeView.resize(300, 100);
}

Widget::~Widget()
{

}

实现效果:



很清楚的看到,作为itemC的子类对象并没有在tableView和listView中显示出来。

所以在组织数据的时候,要根据数据特点,选择合适的视图来对数据进行表示。





评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值