首页 > 编程学习 > 关于qt模型视图 QStandardItemModel 的通俗讲解

为什么需要 模型-视图 框架

模型(就是指的数据组成形式,链表,多叉树,矩阵结构等)和视图(就是实际显示出来的控件)分离,相等于就是前端和后端分离的架构了,这个能够减少代码耦合度,提高复用性。(大家想想网站开发,不就是这么个道理嘛)

原因:模型是一种数据之间的组成架构,我们只需要把数据项itme之间的兄弟关系,父子关系,这些关系对应映射到我们的模型中去(实际上就是根据我们的数据项关系自己指定出各自的行列信息,这个是一次性的),然后视图读取这个模型,update()一下,就会自动更新视图了。

所以,我们就只需要专注于我们的item的数据以及item关系的处理了(比如我们的多叉树数据结构,增加一个孩子啥的操作,由于之前一次性映射好了模型的,所以视图那边会根据这个模型自动更新的),也就是后端这个业务代码了。

模型结构

为了能够让我们更好的设计模型,也就是数据之间的关系,qt提供了QStandardItem、 QStandardItemModel 类来描述这个模型:

  • QStandardItem:表示一个最基本的数据项item,可以包含显示的文本,图标,复选框。而且这个数据项可以可以指定背景色,字体。具有 使能,可编辑的,可选择的,可勾选的等状态。而且还能用于拖动和放下等操作的目标。还能存数据在里面。可以在Model中指定本item所处的行,列(所以这些数据项就能去组成丰富的组织结构,比如列表,树,表格)。比如我们想展示一个人员组织关系树,那么我们自定义一个结构体,叫做struct people,然后挂接上来作为数据索引实体。这个类好像一般不用去子类化,我没研究过。
     
  • QStandardItemModel:表示这些数据项组成起来的总体,对其关系进行管理。它是继承自QAbstractItemModel类,里面提供了很多必须实现的虚函数接口。为了对上面我们自定义的数据关系进行管理,我们也需要子类化QAbstractItemModel,实现对应虚函数。此时每个项item就是对应这里面的 QModelIndex (这里每个QModelIndexitem 是直接指针类型强制转换的),这个就是用来对应这个item的。

此时必须实现下面的虚函数,从而建立出所有的 QStandardItem 在 这个自定义的Model里面的组织结构关系

    QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override;
    QModelIndex parent(const QModelIndex &child) const override;
    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;
    bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override;
    Qt::ItemFlags flags(const QModelIndex &index) const override;

这里拿个函数 QModelIndex parent(const QModelIndex &child) 函数举例,就是要我们实现给出一个child项,返回出它的父节点项。(如果我们不实现这个,当然不行,因为Model也不知道这些项item的行列信息啊,所以视图就没法显示)。那我们当然就根据我们的自定义的数据结构关系(比如自定义的多叉树数据结构),找出它的父节点的地址,然后用这个地址调用QModelIndex  createIndex(row, column, node)函数去创建出一个QModelIndex 返回即可(这就是数据项在模型中的映射过程)。(注意这里可以看出,模型内部还是以行row,列column作为item定位的

有了模型之后,我们只需要将这个模型设置到一个view上去即可,这时候,这个view就会自动根据这个model里面的行列信息进行对应的显示了。

qt提供的视图有哪些

由于数据之间的结构关系,其实就三种,列表,树,矩阵,所以qt提供的视图类也就3种,分别是listview,treeview(描述能力包含listview),tableview(很明显,这个的描述能力可以包含前两者)。当然我们还能自己定义一个视图出来。这些实际上都是继承自QWidget,所以它们都是可视化控件了,只是需要设置一个模型XXModel后(原理:这个视图显示就是读取这个model里面的行列信息进行对应显示了),就能显示出具体东西来了。

函数分析

这里再分析一个函数  int rowCount(const QModelIndex &parent = QModelIndex()) const override;

这个是返回指定父节点的孩子数(每个孩子占一行,其中列为0),前提是给的参数parent是有效的。那这里为什么形参是

parent = QModelIndex()呢,说明如果说我们没有指定形参,那么parent就是QModelIndex(),意思是创建出一个QModelIndex栈对象。从QModelIndex()类的构造函数说明来看,显然这个parent现在是invalid的。既然parent不可用,那么rowCount返回的是什么???

我们的rowCount的说明没有指出来。但是在Model/View Programming部分的Model Classes中的Rows and columns里面有一句话是这样说的:Top level items in a model are always referenced by specifying QModelIndex() as their parent item. 意思是一个model中的顶级item也就是Top level item 的parent,一直都是通过QModelIndex()来指定的

所以,知道一个model的所有行,你就必须使用QModelIndex()来作为其parent。如果你想知道一个model中的某个item下有多少行,你就需要将该item的modelindex作为parent。

所以直接调用 rowCount()函数,啥参数也不给,返回的就是这个模型的总行数。

参考博客:

C++ qt QModelIndex::QModelIndex()怎么解释?_百度知道

Copyright © 2010-2022 mfbz.cn 版权所有 |关于我们| 联系方式|豫ICP备15888888号