声明:本文章只是为了自己学习写的笔记,如需了解具体代码示例或者详细内容请参考<
一.首先来了解一下MVC(Model-View-Controller模型-视图-控制)设计模式
MVC是一种起源于Smalltalk的设计模式,经常用于创建用户界面,模型(Model)是应用对象用于表示数据;视图是(View)是模型的用户界面,用来显示数据;控制(Controller)定义了用户界面对用户输入的反应方式,在MVC之前都是将这三种组件集成在一起,MVC将他们分离,提高了灵活性和重用性,
二.更简单的数据显示框架--模型/视图架构
(1)概要
将视图和控制两个组件结合起来就形成了模型/视图架构,将数据的存储和数据向用户的展示进行了分离,提供了更为简单的框架.数据和界面进行分离,使得相同的数据在多个不同的视图中显示成为可能,而且还可以创建新的视图,而不需要改变底层的数据框架,为了对用户输入进行灵活处理,还引入了委托(也被称为代理Delegate)的概念,使用它可以定制数据的渲染和编辑方式
整体架构如图所示,其中模型与数据源进行通信,为架构中的其他组件提供了接口.视图从模型中获得模型索引(Model Index),模型索引用来表示数据项,在标准的视图中,委托渲染数据项,当编辑项目时,委托使用模型索引直接与模型进行通信
(2)组成
大体上,模型/视图架构中的众多类可以分为3组:模型.视图和委托,其中每一个组件都使用了一个抽象基类来定义,提供了一些通用接口和一些功能的默认实施,模型.视图.委托之间使用信号和槽来实现通信:
[1]当数据源的数据发生改变时,模型发出信号告知视图
[2]当用户与显示的项目交互时,视图发出信号来提供交互信息
[3]当编辑项目时,委托发出信号,告知模型和视图编辑器的状态
1.模型
基于QAbstractItemModel类,提供接口,供视图和委托来访问数据.可以处理各种视图,表现为表格,列表和树等形式
QAbstractListModel,QAbstractTableModel基于列表或者表格的数据结构,为一些常见功能提供了默认的实现
一些现成的模型:
QStringListModel:用来存储一个简单的QString项目列表
QStandardItemModel:管理复杂的树型数据项,每一个数据项可以包含任意的数据
QFileSystemModel 提供了本地文件系统中文件和目录的信息
QSqlQueryModel.QSqlTableModel和QSqlRelationalTableModel用来访问数据库
如果默认的模型无法满足要求可以子类化QAbstractItemModel,QAbstractListModel或者QAbstractTableModel来创建自定义的模型
2.视图
几种不同类型的视图:
QListView将数据项显示为一个列表;
QTableView将模型中的数据显示在一个表格中
QTreeView将模型的数据项显示在具有层次的列表中
如果不能满足要求可以集成QAbstractItemView自己实现
3.委托
委托的基类:QAbstractItemDelegate
默认的委托实现:QStyleItemDelegate
(3)模型类
[1]模型索引
每一块可以同感模型获取的数据都使用一个模型索引来表示,视图和委托都使用这些索引来请求数据来显示,模型索引由QModelIndex类提供,它是对一块数据的临时引用,可以用于检索或者修改模型中的数据,获取一个数据项的模型索引必须指定3个属性:行号,列号和父项的模型索引
[2]行和列
数据项使用行号和列号来定位,但并不是都存储在数组结构中,知识一种约定,确保组件间通信
行列号都是从0开始的,列表模型和表格模型都是以根项为父项的,这些数据项都可以称为顶层数据项,父项的模型索引可以用QModelIndex()表示
[3]父项
在树模型中,如果一个数据项不是顶层数据项,就要指定它的父项索引
[4]项角色
Qt::DisplayRole用来访问可以作为文本显示在视图中的字符串
数据项通常包含不同角色的数据,通常由枚举类型Qt::ItemDataRole来定义,通过为每个角色提供适当的项目数据,模型为视图和委托提供显示,告诉它们数据应该怎样展示给用户
[5]自定义模型类,继承QAbstractListModel,除了构造函数之外,只需要实现两个函数rowCount()和data()
前者返回模型的行数,后者返回指定的模型索引的数据项,headerData(),可以在树和表格视图的表头显示一些内容,如果是层次结构的还需要index()和parent()函数
##1 添加编辑功能
为了使模型可以编辑,需要更改data()函数,然后实现另外两个函数:flags()和setData()
flags返回项目是否是可编辑的,返回一个标识
setData提供委托向模型中设置数据的一条途径
数据被设置后发出dataChanged信号
还需要更改data()中判断条件
##2插入和删除行
需要重新实现isertRows()和removeRows()
,实现过程中首先调用beginInsertRows()告知其他组件指定的行将要发生改变,
改完之后调用endInsertRows
(4)视图类
视图包含了模型中的数据项并将它们呈现给用户,而数据的表示方法可能与底层用于存储数据项的数据结构完全不同,处理项目间的导航以及项目选择的某些方面
##1处理项目选择
视图中被选择的信息存储在一个QItemSelectionModel实例中,这样被选择的项目模型索引就保持在一个独立的模型中,与所有的视图都是独立的,一个模型上设置多个视图时就可以实习请您多个视图之间共享选择
###1当前项目和被选择的项目
###2使用选择模型
属于一个视图的选择模型可以使用这个视图的selectionModel()函数来获得,还可以在多个视图之间使用setSelectionModel()函数来共享选择模型,而且还可以在多个视图之间使用setSelectionModel()函数来共享该选泽模型,所以一般是不需要重新构建一个选择模型的
(5)委托类
为了获得更高的灵活性,交互可以由委托来执行,这些组件提供了输入功能,也负责渲染一些视图中的个别项目.
委托通过实现paint()和sizeHint()函数来使它们可以渲染自身的内容.简单的基于部件的委托可以通过继承QItemDelegate来实现,而不需要使用QAbstractItemDelegate,这样
可以使用这些函数的默认实现,委托的编辑器可以通过两种方式来实现,一种是使用部件来管理编辑过程,另一种是直接处理事件
(6)项目视图的便捷类
QListWidget:提供了一个项目列表
QTreeWidget显示了一个多层次的树结构
QTableWidget提供了一个以项目作为单元的表格,适合用于少量数据的存储和显示
三.其他内容
(1)代理模型
代理模型可以将一个模型中的数据进行排序或者过滤,然后提供给视图进行显示,QT中提供了QSortFilterProxyModel作为标准的代理模型来完成模型中数据的排序和过滤,要使用一个代理模型,则只需要为其设置源模型然后在视图中使用该代理模型即可.
(2)数据-窗口映射器
数据窗口映射器QDataWidgetMapper类在数据模型的一个区域和一个窗口部件间提供了一个映射,这样就可以实现在一个窗口上显示和编辑一个模型中的一行数据
QDataWidgetMapper, toFirst()显示模型中第一行数据,toPdevious()函数和toNext()函数显示模型中上一行和下一行,还有一个toLast()函数可以显示模型中最后一行的数据
总结:模型视图框架是一个很复杂的知识框架,很难一次性掌握,刚开始学习不懂是正常的,需要把握住其核心:模型用来提供数据,视图用来显示数据,委托用来提供项目的特殊显示以及编辑器.