Model/View编程介绍
Qt包含一组使用模型/视图架构来管理数据和用户呈现的关系的视图类。此架构引入的功能分离使开发人员可以更灵活地自定义项的呈现方式,并提供标准的模型接口,以允许各种数据源与现有项视图一起使用。在本文档中,我们简要介绍了模型/视图范例,概述了涉及的概念,并描述了项视图系统的架构。解释了架构中的每个组件,并提供了示例,展示如何使用提供的类。
模型/视图架构
模型-视图-控制器(MVC)是一种来自Smalltalk的设计模式,通常用于构建用户界面。在《设计模式》中,Gamma等人写道:
MVC由三种对象组成。模型是应用程序对象,视图是其屏幕呈现,控制器定义了用户界面对用户输入的反应方式。在MVC之前,用户界面设计倾向于将这些对象合并在一起。MVC将它们解耦以增加灵活性和重用性。
如果视图和控制器对象合并,则结果是模型/视图架构。这仍然将数据存储方式与呈现给用户的方式分开,但提供了一个基于相同原则的更简单的框架。这种分离使得可以在多个不同的视图中显示相同的数据,并实现新的视图类型,而不需要更改基本数据结构。为了允许灵活地处理用户输入,我们引入了委托的概念。在该框架中拥有委托的优点是,它允许自定义渲染和编辑数据项的方式。
模型/视图架构
模型与数据源通信,为架构中的其他组件提供接口。通信的性质取决于数据源类型和模型的实现方式。
视图从模型获取模型索引,这些是对数据项的引用。通过向模型提供模型索引,视图可以从数据源检索数据项。
在标准视图中,委托呈现数据项。当编辑项时,委托使用模型索引直接与模型通信。
一般情况下,模型/视图类可以分为上述三组:模型、视图和委托。这些组件的每个组件都由抽象类定义,它们提供常见的接口和某些情况下的默认实现。抽象类旨在被子类化以提供其他组件所期望的全部功能集;这也允许编写专门的组件。
模型、视图和委托使用信号和槽彼此通信:
来自模型的信号通知视图有关数据源中保存的数据的更改。
来自视图的信号提供有关用户与显示的项目交互的信息。
来自委托的信号在编辑期间用于告知模型和视图编辑器的状态。
模型
所有项模型都基于QAbstractItemModel类。此类定义了由视图和委托用于访问数据的接口。数据本身不必存储在模型中,它可以存储在由单独的类、文件、数据库或其他应用程序组件提供的数据结构或存储库中。
有关模型的基本概念在“模型类”部分中介绍。
QAbstractItemModel提供一个灵活的数据接口,以处理以表格、列表和树形式表示数据的视图。然而,当实现用于列表和表格样式的新模型时,QAbstractListModel和QAbstractTableModel类是更好的起点,因为它们提供了适当的常见功能的默认实现。这些类中的每一个都可以被子类化以提供支持特定类型的列表和表格的模型。
子类化模型的过程在“创建新模型”部分中讨论。
Qt提供了一些可直接使用的模型来处理数据项:
QStringListModel用于存储字符串列表。
QStandardItemModel管理包含任意数据的更复杂的树形结构的项目。
QFileSystemModel提供有关本地文件系统中的文件和目录的信息。
QSqlQueryModel,QSqlTableModel和QSqlRelationalTableModel用于使用模型/视图惯例访问数据库。
如果这些标准模型不满足您的要求,您可以子类化QAbstractItemModel、QAbstractListModel或QAbstractTableModel来创建自己的自定义模型。
视图
针对不同类型的视图提供了完整的实现:QListView显示项目列表,QTableView以表格形式显示模型中的数据,QTreeView按分层列表显示模型数据项。这些类中的每一个都基于QAbstractItemView抽象基类。尽管这些类是可直接使用的实现,但它们也可以被子类化以提供自定义视图。
可用的视图在“视图类”部分中进行了检查。
委托
QAbstractItemDelegate是模型/视图框架中委托的抽象基类。默认委托实现由QStyledItemDelegate提供,并且Qt的标准视图使用它作为默认委托。但是,QStyledItemDelegate和QItemDelegate是独立的替代方案,用于在视图中绘制并为项目提供编辑器。它们之间的区别在于QStyledItemDelegate使用当前样式来绘制其项。因此,我们建议在实现自定义委托或使用Qt样式表时将QStyledItemDelegate用作基类。
代表在“委托类”部分中进行了描述。
排序
在模型/视图架构中有两种处理排序的方法;选择哪种方法取决于您的底层模型。
如果您的模型是可排序的,即如果它重新实现了QAbstractItemModel :: sort()函数,则QTableView和QTreeView都提供API,可以使您以编程方式对模型数据进行排序。此外,您可以通过将QHeaderView :: sortIndicatorChanged()信号连接到QTableView :: sortByColumn()插槽或QTreeView :: sortByColumn()插槽来启用交互式排序(即允许用户通过点击视图的标题栏对数据进行排序)。
如果您的模型没有所需的接口,或者想要使用列表视图来呈现数据,则可以使用代理模型在呈现数据之前转换模型的结构。这在“代理模型”部分中详细介绍。
方便类
为利用Qt的基于项的项视图和表格类的应用程序而派生了许多方便的类。它们不是旨在被子类化的。
此类类别的示例包括QListWidget,QTreeWidget和QTableWidget。
这些类比视图类不够灵活,不能与任意模型一起使用。我们建议您在项视图中使用模型/视图方法来处理数据,除非您强烈需要基于项的类集。
如果您希望利用模型/视图方法提供的功能,同时仍然使用基于项的界面,请考虑使用视图类,如QListView,QTableView和QTreeView与QStandardItemModel。
未完待续。