Qt视图模型框架初识(MVC)


声明:本文章只是为了自己学习写的笔记,如需了解具体代码示例或者详细内容请参考<>第十六章

一.首先来了解一下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()函数可以显示模型中最后一行的数据

总结:模型视图框架是一个很复杂的知识框架,很难一次性掌握,刚开始学习不懂是正常的,需要把握住其核心:模型用来提供数据,视图用来显示数据,委托用来提供项目的特殊显示以及编辑器.