Qt Model/View 学习(2) - QModelIndex索引模型数据

本文深入探讨Qt中的Model/View框架,重点介绍了Model相关类及其核心——QAbstractItemModel。此外,还详细解析了QModelIndex的使用方法,帮助读者更好地理解和使用Qt的Model/View框架。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >


0. 前言

上一篇文章讲了Qt中Model/View框架的起源(和给人的优越感 ),以及它大概是怎么个思路,最后花了不少篇幅讲了为什么要使用Model/View,现在想想多是在给自己打气,好坚持学下去👻。

本文开始介绍有关函数接口了,既然数据Data是用户自定义的,那就从Model开始介绍。

系列文章回顾
Qt Model/View 学习(1) - 是什么和为什么?


1. Model有关类

先上一张Qt有关Model类的UML类图,空心箭头表示泛化关系,也就是派生类指向基类。如果想了解更多一点关于UML类图的知识,可以移步这篇文章
在这里插入图片描述
图中C位自然是QAbstractItemModel了,它继承自QObject获得了信号和槽机制,派生出了诸多Model类,但其中核心就2个:

  • QAbstractListModel:提供一维矩阵模型的抽象基类;既然是抽象类,那我们只能派生自己的类才能使用;
  • QAbstractTableModel:提供表格模型的抽象基类

其它的有:

  • QFileSystemModel:提供本地文件系统的数据模型,使用场景十分受限,也可以先不用过多理会
  • QAbstractProxyModel:提供排序、过滤、或其它数据处理任务的代理模型,暂时可以不用过多理会
  • QStandardItemModel:提供了一种使用控件的Model类,换言之,它Model了,但没有完全Model,在学习Model/View的路上可以不用过多理会
  • QDirModel:官方建议使用性能更好的QFileSystemModel,那可以不用过多理会

所以,虽然继承树似乎内容庞大,但我们只要搞懂QAbstractListModelQAbstractTableModel这俩,就能掌握Model的精髓了,好耶!

而这俩,从名字看就很简单:一个一维数组一个二维数组,而且打开这两个类的文档,篇幅极少,滚动条那么大一个,就这?

在这里插入图片描述


2. Model索引:QModelIndex

先别着急膨胀,QAbstractListModelQAbstractTableModel的文档内容少是因为大部分内容都在QAbstractItemModel中实现了,而打开QAbstractItemModel类的文档就又有些劝退了……

不过换言之,只要掌握了QAbstractItemModel,就能掌握Model的精髓了。

后续将用 “Model类” 来指代从 QAbstractItemModel派生的类;

上一篇文章中讲过,Model是对数据的解析模型,比如20个散装变量,可以被解析成一个4*5的矩阵。而如何去索引矩阵中的数据就是重点了,这需要介绍本小节的主角QModelIndex了,先上一张图:
在这里插入图片描述
以下是核心解释,看完这里基本就掌握索引了:

  1. QModelIndexModel类的索引,基本特征是二维索引,通过row()column()方法获取其位置;

  2. 但它不是纯二维索引,还提供了parent()child()方法获取上层节点下层节点。还提供了sibling()方法,提供rowcolumn的偏移量来获取同一层的兄弟节点

  3. 一般使用Model类的createIndex()方法创建索引,需要提供rowcolumnparent

  4. 使用构造函数创建QModelIndex对象是无效的,无效索引通常被用于指代最顶层对象的parent节点,可通过isValid()方法来判断是否有效,有效表示该对象是某个Model对象的有效索引;

  5. 要获取一个Model类的索引时,使用index()方法获取,但很遗憾该接口一般不是公开的;

    如果设为公开,或许会比较破坏封装性;

  6. QModelIndex对象最好是随用随取,不要指望某个QModelIndex在调用了其它Model函数之后还能起作用,这里暗示QModelIndex是“对位不对人”的,如果希望“对人不对位”,可以使用QPersistentModelIndex类;

    但尽管使用QPersistentModelIndex类也最好先用isValid()断一下,因为有可能索引的对象人没了

最后再补一嘴,为什么Model类的索引被设计成这样?

简单来说,为了适应常见的数据结构:树结构 和 矩阵结构QModelIndex行和列索引使其能够支持矩阵结构parent()child()接口使其能够支持树结构

下图是官方用来说明三种常用模型(列表、表格、树)的图。放到这里来参考的原因是QModelIndex的表示能力是大于以下三种模型的,因为每个QModelIndex对象都可以作为parent,对于每个parent,都可以索引其二维孩子child
在这里插入图片描述
搞清楚如何索引之后,Model类基本就 攻略了30% 了,是不是很简单呢?


3. 小结

  1. Model类主要搞懂QAbstractItemModel即可,搞明白之后由该类派生的QAbstractListModelQAbstractTableModel也会很容易理解;
  2. Model类主要是完成原始数据到模型的映射,所以如何索引模型数据是关键,Qt中采用QModelIndex类来索引模型数据;
  3. QModelIndex类提供了行、列、父、子、兄弟的接口,以此实现对常见的矩阵结构树结构原始数据的支持。

如有错误欢迎指正,共同进步~


今天你学废了吗?

### Qt Model/View 架构概述 QtModel/View 架构是一种设计模式,旨在分离数据处理逻辑(Model)、数据显示方式(View)以及两者之间的交互控制。这种架构不仅提高了代码的可维护性和重用性,还简化了复杂界面的设计[^1]。 #### Model-View 基础组件 - **Model**: 负责管理应用程序的数据及其内部状态。为了使不同类型的视图能够一致地访问这些信息,所有的模型都实现了 `QAbstractItemModel` 接口所规定的公共接口。对于简单的只读场景,可以创建继承自 `QAbstractTableModel` 或者 `QStandardItemModel` 的子类来实现特定功能[^4]。 - **View**: 显示来自关联模型的信息给用户看,并响应用户的输入事件。常见的视图控件有 `QTableView`, `QListView` 和 `QTreeView` 等。当需要展示表格化或者列表式的二维数组型数据时,推荐使用 `QTableView` 并结合自定义的模型类一起工作[^2]。 - **Delegate (代理)**: 定义了如何绘制单个项目并支持编辑操作。默认情况下,大多数内置视图都有自己的标准委托;然而,开发者也可以通过编写新的委托类来自定义外观和行为。 #### 关键类介绍 - **QModelIndex 类**:作为连接视图与模型之间通信的关键桥梁之一,提供了指向具体条目位置的方法。例如,可以通过指定行号、列号及父级索引来获取某个项目的引用,进而对其进行查询或修改操作[^3]: ```cpp // 获取数据 QModelIndex index = model->index(row, column, parentIndex); QVariant data = model->data(index); // 设置数据 model->setData(index, newValue); // 查找父项 QModelIndex parentIndex = index.parent(); ``` #### 创建自定义模型实例 假设要构建一个非常基本的只读表格式模型,则可以从 `QAbstractTableModel` 开始扩展,并重新实现必要的虚函数如 `rowCount()`, `columnCount()` 以及最重要的 `data()` 方法来返回实际存储的内容[^5]: ```cpp class MyModel : public QAbstractTableModel { public: int rowCount(const QModelIndex &parent = QModelIndex()) const override; int columnCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; }; ``` 上述代码片段展示了怎样声明一个新的模型类,并指定了三个核心成员函数——它们分别决定了表格有多少行多少列,还有每个单元格里应该呈现什么文字内容。
评论 9
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值