一、为什么要使用模型索引?
从名字可以看出,他是模型的索引,只要对模型实体(各种xxxModel的实体)施加这个索引,model就会返回数据集中对应的值,或者通过这个索引修改对应数据集中的值。
类比数组就更好理解了,char buf[8] = {'a', 'b','c','d','e'}; ?给定索引3,我们就能从数据集合中读出该值为'c',或者任意修改数据集中的第3个值的值。
当然这个例子不太恰当,因为在这个例子中buf这个变量,不仅是数据Data,而且是模型Model。在真正的MVC中,Data的实体是对用户隐藏的,用户只能通过Model来读写Data中的内容,也即只有模型才知道如何获取数据View是不知道,参见我的本系列前面的博文,这样的好处是用户不必关心Data在系统底层的组织方式。
?
二、为了使数据的显示同存储分离,引入了模型索引(model index)的概念。通过模型索引,可以访问模型的特定元素的特定部分。视图和委托使用模型索引来请求所需要的数据。由此可以看出,只有模型自己需要知道如何获得数据,模型所管理的数据类型可以使用通用的方式进行定义。模型索引保存有创建的它的那个模型的指针,使同时操作多个模型成为可能。
? 模型索引提供了所需要的信息的临时索引,用于通过模型取回或者修改数据。由于模型随时可能重新组织其内部的结构,因此模型索引很可能变成不可用的,此时,就不应该保存这些数据。如果你需要长期有效的数据片段,必须创建持久索引。持久索引保证其引用的数据及时更新。临时索引(也就是通常使用的索引)由QModelIndex类提供,持久索引则是?QPersistentModelIndex?类。
为了定位模型中的数据,需要三个属性:行号、列号以及父索引。
QT中,Model接口由QAbstractItemModel类进行定义。不管底层数据是如何存储的,只要是QAbstractItemModel的子类,都提供一种表格形式的层次结构。视图利用统一的转换来访问模型中的数据。模型内部数据的组织方式并不一定和视图中数据的显示相同。一般来说,内置的这3种约定,已足以满足大多编程需求了。是这样约定的,见下图:
? ? ? ? ? ? ??
对于列表,指定行号就可以唯一确定一个格子;
对于表格,指定行号、列号就可以唯一确定一个格子;
对于树形,指定行号、列号、父索引,才可以唯一确定一个格子;
QT为了使列表、表格、树,三者形式统一而做出的妥协,QT将这三者的item访问方式都规定为:必须提供3个参数:行号、列号、父索引。
只是对于列表模型、表格模型,接口函数已经有了默认参数而已,父索引填QModelIndex的默认构造时,代表最顶层的根节点项Root Item。
直接看官方例子可能会容易,以上图的表格模型为例,看看是如何访问ABC单元格的:
对于表格模型,上述代码的第3参均可不写,因为默认参数就是root节点,也即默认的构造QModelIndex()。
再以上图的树形模型为例,看看是如何访问ABC单元格的:
上述代码中,只要看懂了如何访问根节点的儿子A的儿子B,也即如何访问根节点的孙子B,那就算掌握了QModelIndex的精髓。
三、QModelIndex
?是 Qt 中用于表示数据模型中项的索引的类。它包含了描述项位置的行号、列号和父索引等信息,用于在数据模型和视图之间进行数据交互。
QModelIndex
?的主要成员函数和用途如下:
row()
:返回项的行号。column()
:返回项的列号。parent()
:返回项的父索引,用于构建层级结构的模型。child()
:返回指定行列的子项的索引。isValid()
:检查索引是否有效,即是否引用一个有效的项。data()
:从模型中获取索引对应项的数据。setData()
:将数据设置给索引对应项。flags()
:返回索引对应项的标志,用于指示项的属性,例如是否可编辑、是否可选择等。使用?QModelIndex
,你可以通过行号和列号或者父索引来访问数据模型中的特定项。它在模型和视图之间提供了一种统一的方式来传递和操作项的位置信息。
在大多数情况下,你无需直接创建?QModelIndex
?对象,而是通过调用数据模型的成员函数(例如?index()
、parent()
、child()
)来获取索引对象。这些成员函数会根据模型的结构和布局返回正确的索引。