MVC(Model-View-Controller)是一种设计模式。
- Model(模型)是应用对象,用来显示模型
- View (视图)是用户界面,用来显示数据
- Controller(控制)定义用户界面对用户输出的反映方式
模型/视图类可以分为上述三组:模型、视图和委托。这些组件中的每一个都由抽象类定义,这些抽象类提供通用接口,在某些情况下,还提供功能的默认实现。
模型:
模型的基类为:QAbstractItemModel类,此类定义视图和委托用于访问数据的接口。数据本身不必存储在模型中;它可以保存在由单独的类、文件、数据库或某些其他应用程序组件提供的数据结构或存储库中。常用的视图有:表格、树、列表。
Qt提供了一些现成的模型,可用于处理数据项:
- QStringListModel 用来存储一个简单的QString列表
- QStandardItemModel 管理复杂的树形结构数据项,,每一个数据项可以包含任意的数据
- QFileSystemModel提供本地文件系统中文件和目录的信息
- QSqlQuerryModel,QSqlTableModel和QSalRelationTableModel 用来访问数据库
无法满足需求的话,可以子类化QAbstractItemModel、 QAbstractListModel、QAbstractTableModel来创建自定义的模型
视图:
在Qt中:QListView列表视图,QTreeView树视图、QTableView表格视图,这些类都基于QAbstractItemView抽象基类。
委托:
QAbstractItemDelegate是委托的抽象基类,子类主要分为以下两种:
- QStyledItemDelegate类(默认委托类)使用当前样式来绘制项目
- QItemDelegate类
- QStyledItemDelegate和QItemDelegate是绘制和为视图中的项目提供编辑器的独立替代方法。
注意:使用时只能选择一种,一般的话使用QStyledItemDelegate
使用模型和视图:
使用QFileSystemModel 文件模型,并用QListView 和QTreeView显示
#include "widget.h"
#include <QApplication>
#include<QFileSystemModel>//模型
#include<QSplitter>
#include<QTreeView>//视图
#include<QListView>
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
QSplitter * sp=new QSplitter;
QFileSystemModel model;//创建文件系统模型
model.setRootPath(QDir::currentPath());//设置要监视的目录
QTreeView *tree=new QTreeView(sp);//创建树形视图
tree->setModel(&model);//设置模型
tree->setRootIndex(model.index(QDir::currentPath()));//指定根索引
QListView *list=new QListView(sp);//创建列表视图
list->setModel(&model);
list->setRootIndex(model.index(QDir::currentPath()));//指定根索引
sp->show();
return a.exec();
}
模型类:
常用的三种模型为:list(列表) table (表格) tree(树)
1. 模型索引:
为了确保数据的表示形式与访问数据的方式分开,引入了模型索引的概念。可以通过模型获得的每条信息都由模型索引表示。视图和委托使用这些索引来请求要显示的数据项
模型索引提供对信息片段的临时引用,并可用于通过模型检索或修改数据 ,但模型可能会不时重组其内部结构,因此模型索引可能会变得无效。
- 临时的模型索引由 QModelIndex提供
- 持久模型索引由QPersistentModelIndex类提供 (需要长时间对信息引用)
获取模型索引的话,必须指定行号、列号和父项的模型索引。
2.行和列:
在其最基本的形式中,模型可以作为一个简单的表进行访问(行和列都是从0开始),可以通过向模型指定其行号和列号来检索有关任何给定项目的信息。
QModelIndex index=model->index(行,列,父项)
在表格和列表模型中,所有数据项都是以根项(Root Item)为父项(也称为顶层数据项)获取顶层数据项使用 QModelIndex() 表示。
以表格模型为例:
QModelIndex indexA =model->index(0,0,QModelIndex());//获取A的模型索引
QModelIndex indexB =model->index(1,1,QModelIndex());//获取B的模型索引
QModelIndex indexC =model->index(2,1,QModelIndex());//获取C的模型索引
3.父项:
在表或列表视图中使用数据时,模型提供的项数据的类似表的界面是理想的选择;行号和列号系统与视图显示项目的方式完全一致。但是,树视图等结构要求模型向其中的项公开更灵活的接口,因此,每个项也可以是另一个项表的父项,其方式与树视图中的顶级项可以包含另一个项列表的方式大致相同。
树模型:
QModelIndex indexA =model->index(0,0,QModelIndex());//获取A的模型索引
//指定父项为A
QModelIndex indexB =model->index(1,0,indexA);//获取B的模型索引
QModelIndex indexC =model->index(2,1,QModelIndex());//获取C的模型索引
3.项目角色:
模型中的项可以为其他组件执行各种角色,从而允许为不同情况提供不同类型的数据,例如Qt::DisplayRole用于访问视图中的字符串。通常,项目中包含许多不同的角色的数据,标准角色由Qt::ItemDataRole定义。
模型传递与项目对应的模型索引,并通过指定一个角色来获取我们想要的数据类型,从而向模型询问项目的数据:
QVariant value=model->data(index,role);
常见的角色类型:
Qt::DisplayRole | 要以文本形式呈现的关键数据 |
Qt::DecorationRole | 要以图标形式呈现为修饰的数据 |
Qt::EditRole | 适合在编辑器中编辑的表单中的数据 |
Qt::ToolTipRole | 项目的工具提示中显示的数据 |
Qt::StatusTipRole | 状态栏中显示的数据 |
Qt::WhatsThisRole | 在“What is this?”模式下为项目显示的数据 |
Qt::SizeHintRole | 将提供给视图的项的大小提示 |
Qt::FontRole | 用于使用默认委托呈现的项的字体 |
Qt::TextAlignmentRole | 使用默认委托呈现的项的文本对齐方式 |
Qt::BackgroundRole | 用于使用默认委托呈现的项的背景画笔 |
Qt::ForegroundRole | 用于使用默认委托呈现的项目的前景色画笔(通常为文本颜色) |
Qt::CheckStateRole | 此角色用于获取项目的已检查状态 |
Qt::InitialSortOrderRole | 此角色用于获取标题视图节的初始排序顺序 |
Qt::UserRole | 可用于特定于应用程序的第一个角色 |
例子:使用QStandardItemModel 创建一个模型,并获取角色类型
- 获取模型的父项使用 invisibleRootItem()
- 设置ModelIndex时 父项的表示为QModelIndex()
QStandardItemModel model;//创建一个标准模型
QStandardItem *ParentItem=model.invisibleRootItem();//获取根项
QStandardItem *item=new QStandardItem;//创建一个标准子项
item->setText("11111111");//设置内容
QPixmap pixmap(40,40);//创建一个图片
pixmap.fill("red");
item->setIcon(QIcon(pixmap));//设置图标
item->setToolTip("index1");
ParentItem->appendRow(item);//添加子项
//修改父项
ParentItem=item;//将item设父项
QStandardItem *item1=new QStandardItem;//创建一个标准子项
item1->setText("22222222");//设置内容
QPixmap pixmap1(40,40);//创建一个图片
pixmap1.fill("blue");
item1->setIcon(QIcon(pixmap1));//设置图标
item1->setToolTip("index2");
ParentItem->appendRow(item1);//添加子项
//使用setData()来设置
QStandardItem *item2=new QStandardItem;//创建一个标准子项
QPixmap pixmap2(40,40);//创建一个图片
pixmap2.fill("green");
item2->setData("33333333",Qt::EditRole);//设置文本
item2->setData(QIcon(pixmap2),Qt::DecorationRole);//设置图标
item2->setData("index3",Qt::ToolTipRole);//设置工具提示
ParentItem->appendRow(item2);//添加子项
//创建一个视图
QTreeView view;
view.setModel(&model);
view.show();
//输出项目的内容
QModelIndex indexA=model.index(0,0,QModelIndex());//获取item
qDebug()<<model.rowCount(indexA);//获取该索引的子项
qDebug()<<model.data(indexA,Qt::ToolTipRole).toString();//获取工具提示
qDebug()<<model.data(indexA,Qt::EditRole).toString();//获取文本框内容
qDebug()<<model.data(indexA,Qt::DecorationRole);//获取图标
视图类:
在模型/视图体系结构中,视图从模型中获取数据项并将其呈现给用户。数据的呈现方式不需要类似于模型提供的数据的表示形式,并且可能与用于存储数据项的基础数据结构完全不同。
内容和表示的分离通过使用 QAbstractItemModel 提供的标准模型接口、QAbstractItemView 提供的标准视图接口以及使用以一般方式表示数据项的模型索引来实现。视图通常管理从模型获取的数据的整体布局。它们可以自己呈现单个数据项,也可以使用委托来处理呈现和编辑功能。除了显示数据外,视图还处理项目之间的导航以及项目选择的某些方面。
QSplitter * sp=new QSplitter;
QFileSystemModel model;//创建文件系统模型
model.setRootPath(QDir::currentPath());//设置要监视的目录
QTreeView *tree=new QTreeView(sp);//创建树形视图
tree->setModel(&model);//设置模型
tree->setRootIndex(model.index(QDir::currentPath()));//指定根索引
QListView *list=new QListView(sp);//创建列表视图
list->setModel(&model);
list->setRootIndex(model.index(QDir::currentPath()));//指定根索引
QTableView *table=new QTableView(sp);//创建表格视图
table->setModel(&model);
table->setRootIndex(model.index(QDir::currentPath()));//指定索引
sp->show();
处理项目的选择 :
处理视图的选择的机制由QItemSelectionModel类提供,默认情况下所有标准视图都构造自己的选择模型,并以正常方式与它们进行交互。
- selectionModel()获取选择模型
- setSelectionModel()指定选择模型
当我们想要为同一模型数据提供多个一致的视图时,控制视图使用的选择模型的能力非常有用
视图之间共享选择
QSplitter * sp=new QSplitter;
QFileSystemModel model;//创建文件系统模型
model.setRootPath(QDir::currentPath());//设置要监视的目录
QTreeView *tree=new QTreeView(sp);//创建树形视图
tree->setModel(&model);//设置模型
tree->setRootIndex(model.index(QDir::currentPath()));//指定根索引
QTableView *table=new QTableView(sp);//创建表格视图
table->setModel(&model);
table->setRootIndex(model.index(QDir::currentPath()));//指定索引
table->setSelectionModel(tree->selectionModel());//实现同步
sp->show();
委托类:
与模型-视图-控制器模式不同,模型/视图设计不包括用于管理与用户交互的完全独立的组件。通常,视图负责向用户呈现模型数据,并负责处理用户输入。为了在获取此输入的方式上具有一定的灵活互由委托执行。这些组件提供输入功能,还负责呈现某些视图中的单个项。用于控制委托的标准接口在 QAbstractItemDelegate 类中定义。
委托通过实现paint()和sizeHint()函数来使它们可以渲染自身的内容,简单的基于部件的委托可以通过QItemDelegate来实现,不需要QAbstractItemDelegate,这样可以使用这些函数的默认项实现
使用现有委托:
标准委托类使用QStyledItrmDelegate的实例来提供编辑工具,所有标准角色都由标准视图使用的默认委托处理。
- itemDelegate()返回委托
- setItenDelegate()设置委托
参考文档:
QAbstractItemDelegate