第55课 - 模型视图设计模式

(上)

1、模型视图设计模式 

模型视图设计模式的核心思想 

      -模型(数据)与视图(显示)相分离 

      -模型对外提供标准接口存取数据(不关心数据如何显示

      -视图自定义数据的显示方式(不关系数据如何组织存储) 

 

模型视图模式的直观理解 

模型视图模式的工作机制 

      -当数据发生改变时 

                  ★模型发出信号通知视图

      -当用户与视图进行交互时 

                  ★视图发出信号提供交互信息 

2、Qt中的模型视图

Qt中的模型类层次结构 

Qt中视图类的层次结构 

关键技术问题: 

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

       深入理解: 

           在Qt中,不管模型以什么结构组织数据,都必须为每一个数据

           提供独一无二的索引视图通过索引访问模型中的具体数据。 

 

模型视图编程示例 

3、编程实验 

模型视图结构的初探    55-1.pro 

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui/QWidget>
#include <QFileSystemModel>
#include <QTreeView>

class Widget : public QWidget
{
    Q_OBJECT
    
    QFileSystemModel m_fsModel; //定义文件系统模型,用于组织文件夹数据
    QTreeView m_treeView; //定义树形显示视图
public:
    Widget(QWidget *parent = 0);
    ~Widget();
};

#endif // WIDGET_H

Widget.cpp

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

Widget::Widget(QWidget *parent)
    : QWidget(parent)
{
    m_treeView.setParent(this); //m_treeView不过就是个组件,父组件为Widget对象
    m_treeView.move(10, 10);
    m_treeView.resize(500, 300);

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

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

    m_treeView.setRootIndex(m_fsModel.index(QDir::currentPath())); 
    //为树形显示视图根部设置索引,指明数据从根开始呈现
    //索引从模型得到
}

Widget::~Widget()
{
    
}

          文件系统模型用于组织文件夹数据当目录发生变化时

          模型发出信号通知视图 ,于是此树状视图就重新呈现数据

4、小结 

Qt中内置的支持了模型视图的开发方式 

模型用于组织数据源,不关心数据的显示方式 

视图用于定义数据的显示方式,不关心数据的组织方式 

Qt中的模型必须为每一个数据提供独一无二的索引 

Qt中的视图通过索引访问模型中的数据 

(中)

1、模型视图设计模式 

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

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

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

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

2、模型中的索引 

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

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

QModelIndex是Qt中的模型索引类

    -包含具体数据的访问途径 

    -包含一个指向模型的指针 

索引的意义 

                               模型负责组织数据,模型通过调用createIndex创建索引,

                               通过模型的index函数获得索引,视图通过索引获得想要显示的数据

索引中的行和列 

                 - 线性模型可以使用(row, column)作为数据索引 

                               问题  :  只用行和列描述数据索引是否足够通用? 

                                          思考  : 如何索引以树形结构组织的数据? 

                   

模型中的通用树形结构 

 

                     解决方案: 

                               Root为虚拟节点 用于统一所有数据到同一树中 

                               同一节点的子节点以递增的方式编号 

                               通过(index, parent)的方式确定节点 

  

模型中数据索引的通用方式 

3、编程实验 

数据索引深入理解  56-1.pro 

 Widget.h

#ifndef WIDGET_H
#define WIDGET_H

#include <QtGui/QWidget>
#include <QPlainTextEdit>
#include <QFileSystemModel>

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

#endif // WIDGET_H

Widget.cpp

#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_fsm, SIGNAL(directoryLoaded(QString)), this, SLOT(onDirectoryLoaded(QString)));
    //This signal is emitted when the gatherer thread has finished to load the path.

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

void Widget::onDirectoryLoaded(const QString& path)
{
    QModelIndex root = m_fsm.index(path);
    QByteArray array;
    QBuffer buffer(&array);

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

        out << m_fsm.isDir(root) << endl; 
        out << m_fsm.data(root).toString() << endl;
        out << root.data().toString() << endl; //可以直接通过索引取数据
        out << &m_fsm << endl;
        out << root.model() << endl; //索引包含一个指向模型的指针 
        out << m_fsm.filePath(root) << endl;
        out << m_fsm.fileName(root) << endl;
        out << endl;

        //Returns the number of rows under the given parent
        for(int i=0; i<m_fsm.rowCount(root); i++)
        {
            QModelIndex ci = m_fsm.index(i, 0, root);

            out << ci.data().toString() << endl;
        }

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

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

        m_edit.insertPlainText(in.readAll());

        buffer.close();
    }
}

Widget::~Widget()
{
    
}

        

                                               这里遍历行,固定为0列

                                               若固定1列打印日期,等等

4、小结 

索引是访问模型中具体数据的约定方式 

获取索引的通用形式为三元组(row, column, parent) 

索引在需要时由模型实时创建 

使用空索引作为父节点表示顶层数据元素 

特殊的模型可以自定义特殊的索引获取方式 

(下)

1、问题 

不同的视图如何显示同一个模型中的数据? 

2、模型视图设计模式 

Qt中标准模型定义   

数据角色的概念 

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

       -模型必须为数据设置特定数据角色(数据属性) 

       -数据角色用于提示视图数据的作用 

       -数据角色是不同视图以统一风格显示数据的标准 

Qt中的数据角色定义 

数据角色的意义 

       -定义了数据在特定系统下的标准用途 

       -不同的视图可以通过相同标准显示数据 

注意: 

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

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

 

3、编程实验 

自定义数据模型,数据模型中的角色   57-1.pro 

Widget.h

#ifndef WIDGET_H
#define WIDGET_H

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

class Widget : public QWidget
{
    Q_OBJECT
    
    QStandardItemModel m_model;
    QTableView m_tableView;
    QListView m_listView;
    QTreeView m_treeView;

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

#endif // WIDGET_H

Widget.cpp

#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()
{
    //Returns the model's invisible root item.
    QStandardItem* root = m_model.invisibleRootItem();
    
    //The QStandardItem class provides an item for use with the QStandardItemModel class.
    QStandardItem* itemA = new QStandardItem();
    QStandardItem* itemB = new QStandardItem();
    QStandardItem* itemC = new QStandardItem();
    QStandardItem* itemChild = new QStandardItem();

    //Sets the item's data for the given role to the specified value.
    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);

    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()
{
    
}

4、小结 

模型中的数据有附加的角色属性 

数据角色定义了数据显示的标准方式 

数据角色用于提示视图数据的作用 

视图可以自由解析或者忽略数据的角色信息

猜你喜欢

转载自blog.csdn.net/qq_39654127/article/details/81745030