(上)
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、小结
模型中的数据有附加的角色属性
数据角色定义了数据显示的标准方式
数据角色用于提示视图数据的作用
视图可以自由解析或者忽略数据的角色信息