QT基础:23---Model/View(模型/视图)结构简介

Model/View的概念、组成结构

QT基础:23---Model/View(模型/视图)结构简介

QT基础:23---Model/View(模型/视图)结构简介

Model/View的组成结构:

将界面组件与锁边机的数据分离开来,又通过数据源的方式连接起来,是处理界面与数据的一种较好的方式。QT使用Model/View结构来处理这种关系,基本结构如下:

QT基础:23---Model/View(模型/视图)结构简介

  • 代理功能:

QT基础:23---Model/View(模型/视图)结构简介

QT基础:23---Model/View(模型/视图)结构简介

一、数据模型

  • 所有的基于项数据的数据模型都是基于QAbstractItemModel类的,这个类定义了试图组件和代理存放数据的接口。数据无需存储在数据模型里,数据可以是其他类、文件、数据库或任何资源。

Qt中与数据模型相关的几个主要的类的层次结构如下图所示:

QT基础:23---Model/View(模型/视图)结构简介

上图的抽象类是不能直接使用的,需要由子类继承来实现一些纯虚函数。Qt提供了一些模型类用于项数据的处理,见下表:

QT基础:23---Model/View(模型/视图)结构简介

  • 注意:如果这些现有的数据模型无法满足需求,用户可以从QAbstractItemModel、QAbstractListModel、QAbstractTableModel继承,生成自己定制的数据模型类

数据模型的表现形式:

  • 不管数据模型的表现形式是怎么样的,数据模型中存储数据的基本单元都是像,每个项有一个行号、列号,还有一个父项
  • 在列表和表格模式下,所有的项都有一个相同的顶层项
  • 在树状结构中,行号、列号、父项稍微复杂一点,但是由这3个参数完全可以定义一个项的位置,从而存取项的数据

QT基础:23---Model/View(模型/视图)结构简介

模型索引:

  • 为了保证数据的表示与数据存取方式隔离,数据模型中引入了模型索引的概念
  • 通过数据模型存储的每个数据都有一个模型索引,视图组件和代理都通过模型索引来获取数据
  • QModelIndex表示模型索引的类。模型索引提供数据存取的一个临时指针,用于通过数据模型提取或修改数据
  • 因为模型内部组织数据的结构随时可能改变,所以模型索引是临时的。如果需要使用持久性的数据模型,则要使用QPersistentModelIndex类

行号、列号:

  • 数据模型的基本形式是使用行和列定义的表格数据,但并不意味着底层的数据使用二维数组存储的,使用行和列只是为了组件之间交互方便的一种规定。通过模型索引的行号、列号就可以存取数据
  • 要获取一个模型索引,必须提供3个参数:行号、列号、父项的模型索引

例如,上图的数据模型中的3个数据项A、B、C,获取其数据模型索引的代码如下:

QT基础:23---Model/View(模型/视图)结构简介

  • 在创建模型索引的函数中需要传递行号、列号和父项的模型索引。对于列表和表格模型的数据模型,顶层节点总是用QModelIndex()表示

父项:

  • 当数据模型是列表或表格时,使用行号、列号存储数据比较直观,所有数据项的父项就是顶层项;当数据模型是树状结构时,情况比较复杂(树状结构中,项一般习惯于称为节点),一个节点可以有父节点,也可以是其他节点的父节点,在构造数据项的模型索引时,必须指定正确的行号、列号和父节点

对于上图的树状数据模型,节点A和节点C的父节点是顶层节点,获取模型索引的代码是:

QT基础:23---Model/View(模型/视图)结构简介

但是,节点B的父节点是节点A,节点B的模型索引由下面的代码生成:

QT基础:23---Model/View(模型/视图)结构简介

项的角色:

  • 在为数据模型的一个项设置数据时,可以赋予其不同项的角色的数据

例如,数据模型类QStandardItemModel的项数据类是QStandardItem,其设置数据的函数是:

QT基础:23---Model/View(模型/视图)结构简介

  • value是需要设置的数据,role是设置数据的角色。一个项可以有不同角色的数据,用于不同的场合
  • role是Qt::ItemDataRole枚举类型,有多种值,如Qt::DisplayRole角色是在视图组件中显示的字符串,Qt::ToolTipRole是鼠标提示的消息,Qt::UserRole可以自定义数据。项的标准角色是Qt::DisplayRole

获取一个项的数据时也需要指定角色,以获取不同角色的数据:

QT基础:23---Model/View(模型/视图)结构简介

  • 为一个项的不同角色定义数据,可以告知视图组件和代理组件如何显示数据。例如,下图中,项的DisplayRole数据是显示的字符串,DecorationRole是用于装饰显示的数据性,ToolTipRole定义了鼠标提示信息。不同的视图组件对各种角色数据的解释和显示可能不一样,也可能忽略某些角色的数据

QT基础:23---Model/View(模型/视图)结构简介

二、视图组件

视图组件就是显示数据模型的数据的界面组件,Qt提供的视图组件如下:

QT基础:23---Model/View(模型/视图)结构简介

  • 如何配合数据模型使用:视图组件在显示数据时,只需要调用视图类的setModel()函数,为视图组件设置一个数据模型就可以实现视图组件与数据模型之间的关联,在视图组件上的修改将自动保存到关联的数据模型里,一个数据模型可以同时在多个视图组件里显示数据

视图组件与便利类的关系:

  • 便利类就是QListWidget、QTableWidget、QTreeWidget
  • 视图组件直接从QAbstractItemView继承而来,而便利类则从相应的视图类继承而来

QT基础:23---Model/View(模型/视图)结构简介

  • 视图组件类的数据采用单独的数据模型,视图组件不存储数据
  • 便利类则为组件的每个节点或单元格创建一个项,用项存储数据、格式设置等
  • 所以,便利类没有数据模型,它实际上使用项的方式继承了数据模型的功能,这样就将界面与数据绑定了
  • 所以,便利类缺乏对大型数据源进行灵活处理的能力,适用于小型数据的显示和编辑

三、代理

  • 概念:代理就是在视图组件上为编辑数据提供的编辑器,如在表格组建中编辑一个单元格的数据时,缺省的是使用一个QLineEdit编辑框
  • 代理负责从数据模型获取相应的数据,然后显示在编辑器里,修改数据后,又将其保存到数据模型中
  • QAbstractItemDelegate是所有代理类的基类,作为抽象类,它不能直接使用。它的一个子类QStyleItemDelegate,是Qt的视图组件缺省使用的代理类
  • 对于一些特殊的数据编辑需求,例如只允许输入整型数,使用一个QSpinBox作为代理组件更恰当,从列表中选择数据时使用一个QComboBox作为代理组件更好。这是,就可以从QStyleItemDelegate继承创建自定义代理类