上一篇文章基于QAbstractItemModel新建了一个用户模型类,此文紧接上一篇文章来对用户模型进行具体设计和实现。

QAbstractItemModel

生成的用户模型给出了模型的标准接口;但是任何模型都是对数据封装,那么必然需要专用对象来储存数据,而这个储存数据的对象就具有十分多的形式,可以是Qt/C++容器、数组、字符串、文件、SQL对象等。而用户类就是将用户各种形式的数据储存方式转为统一的模型接口以供其他类(如视图类)来使用,同时将其他类的操作转化到对具体数据对象的具体操作(如写、添加、删除等)。

此处为了简化接口,构造一个常见的Table类用户模型,模型一共两列,每行第一列储存“Name“格式是QString,每行第二列储存“Age”格式是int。采用QMap<QString,int>来储存每一行的数据,采用QVector<QPair<QString,int>>来储存所有行的数据。在h文件中私有属性定义一个数据储存指针:
QVector<QPair<QString,int>> *m_dataVector = nullptr; //新建一个储存数据的序列对象,每个元素(行)两个值,一个储存姓名、一个储存年龄

同时定义一个QList m_headName来储存表头名称。
在cpp构造函数中对数据储存指针进行初始化并给数据列表初始化一个默认值:

CustomItemModel::CustomItemModel(QObject *parent): QAbstractItemModel(parent),m_dataVector(new QVector<QPair<QString,int>>{})
{m_dataVector->push_back({"Bob",30});m_headName = {"Name","Age"};

在析构函数中对数据列表进行析构:

CustomItemModel::~CustomItemModel()
{if(m_dataVector) {m_dataVector->clear();delete m_dataVector;m_dataVector=nullptr;}
}

构造好数据储存形式之后,下一步就可以对用户模型的虚函数进行实现。这些虚函数的实现与用户自定义的数据结构和需求精密相关,没有具体实现方式可以参考,需根据具体场景来编写实现代码。

  • headerData(int section, Qt::Orientation orientation, int role)

获取表头信息,orientation表示表头方向,分为水平和垂直;section表示表头位置,如果是行,表示第几列;如果是列,表示第几行。Role表示表头角色信息。Model模型每个元素提供的role主要与如下一些。

此处我们只关心行表头,同时也只希望返回表头的显示信息即DisplayRole的值。一个简单的表头信息获取实现代码如下:

QVariant CustomItemModel::headerData(int section, Qt::Orientation orientation, int role) const
{if(role!=Qt::DisplayRole)return QVariant();if(orientation==Qt::Vertical)return QVariant(section);if(orientation==Qt::Horizontal){if(section==0) return QVariant(m_headName[0]);if(section==1) return QVariant(m_headName[1]);}return QVariant();
}
  • setHeaderData()

该函数实现对表头文件信息的修改,和上一个函数正好构成一对函数。同样,我们此处也只是暂时修改一下行表头的信息。

bool CustomItemModel::setHeaderData(int section, Qt::Orientation orientation, const QVariant &value, int role)
{if (value != headerData(section, orientation, role)) {if(role!=Qt::EditRole) return false;if(orientation==Qt::Vertical) return false;if(section==0) m_headName[0]= value.toString();if(section==1) m_headName[1]=value.toString();emit headerDataChanged(orientation, section, section);return true;}return false;
}
  • index(int row, int column, const QModelIndex &parent)

index根据表格中的父节点parent下的某行row和某列column信息获取对应的QModelIndex对象信息。如果行和列超出范围,返回一个无效的QModelIndex()。

QModelIndex CustomItemModel::index(int row, int column, const QModelIndex &parent) const
{if(row>m_dataVector->size()-1 || row < 0) return  QModelIndex();if(column>1 || column<0) return QModelIndex();return createIndex(row,column);
}
  • parent(const QModelIndex &index)

函数实现获取某个index的父节点,由于此处是表格模型,默认认为父节点是无效空节点。

QModelIndex CustomItemModel::parent(const QModelIndex &index) const
{// FIXME: Implement me!return QModelIndex();
}
  • rowCount(const QModelIndex &parent)

获取某个父节点parent下的模型行数,直接范围数据列表的size即可:

int CustomItemModel::rowCount(const QModelIndex &parent) const
{return m_dataVector->size();
}
  • columnCount(const QModelIndex &parent)

返回某个父节点下的模型列数,此处直接返回2:

int CustomItemModel::columnCount(const QModelIndex &parent) const
{return 2;
}
  • hasChildren(const QModelIndex &parent)

判断某个节点是否还有子节点,这种判断对于树形模型来说十分重要,表格模型默认都没有子节点:

bool CustomItemModel::hasChildren(const QModelIndex &parent) const
{return false;
}
  • canFetchMore(const QModelIndex &parent)

判断数据是否还有更多数据节点可以获取:

bool CustomItemModel::canFetchMore(const QModelIndex &parent) const
{return false;
}
  • fetchMore(const QModelIndex &parent)

由于没有更多数据,此处不做额外处理:

void CustomItemModel::fetchMore(const QModelIndex &parent)
{// FIXME: Implement me!
}
  • data(const QModelIndex &index, int role)

data()和setData()函数是十分钟的对模型元素进行操作的函数。data()函数根据角色和索引号获取到对应的元素值。如下几个角色比较关键:

此处我们暂时只关心DisplayRole的值,该函数的实现代码如下,此处使用switch来判断不同角色对应的值,后面可以做一些比较全面的补充:

QVariant CustomItemModel::data(const QModelIndex &index, int role) const
{if (!index.isValid())return QVariant();if(index.row()>m_dataVector->size()-1 || index.row()<0 || index.column()<0  ||index.column()>1)return QVariant();switch(role){case Qt::DisplayRole:{if(index.column()==0){QString name = m_dataVector->at(index.row()).first;return QVariant(name);}if(index.column()==1){int age = m_dataVector->at(index.row()).second;return QVariant(age);}break;}
  • setData(const QModelIndex &index, const QVariant &value, int role)

该函数将某个元素(index指定)某个角色role的值设置为value的值,此处关注对显示字符串的编辑角色,实现代码如下:

bool CustomItemModel::setData(const QModelIndex &index, const QVariant &value, int role)
{if (data(index, role) != value){switch (role){case Qt::EditRole:{QString name = m_dataVector->at(index.row()).first;int age = m_dataVector->at(index.row()).second;if(index.column()==0){QPair<QString,int> pair(value.toString(),age);m_dataVector->replace(index.row(),pair);}if(index.column()==1){QPair<QString,int> pair(name,value.toInt());m_dataVector->replace(index.row(),pair);}emit dataChanged(index, index, QVector<int>() << role);return true;}
  • flags(const QModelIndex &index)

获取某个元素(index指定的)的所有属性标志位,多个属性采用按位或“|”算法链接,此处我们先设置如下标志位属性。

Qt::ItemFlags CustomItemModel::flags(const QModelIndex &index) const
{if (!index.isValid())return Qt::NoItemFlags;return Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable |Qt::ItemIsUserCheckable; // FIXME: Implement me!
}

本文对几个关键的虚函数进行了实现,下一文将继续介绍剩下几个虚函数的实现,同时将模型集成到视图并显示出来。


欢迎同好沟通交流,批评指正,欢迎关注我的公号:不如起而行之

Qt系列文章之 QAbstractItemModel(中)相关推荐

  1. qt系列文章之激光雷达通信

    qt系列文章之激光雷达通信 提示:这里可以添加系列文章的所有文章的目录,目录需要自己手动添加 例如:第一章 qt通信学习入门之激光雷达通信 文章目录 qt系列文章之激光雷达通信 前言 0.效果 一.通 ...

  2. Qt系列文章001-Qt下载安装

    1 Qt下载 这边只介绍具体的下载地址,本文也是以Qt5.x系列为主,其他版本不涉及,因为Qt目前的大版本是5.x系列,最新版本最近刚更新到5.15.Qt6 于2020年年底发布,预览版已经出了,我尝 ...

  3. BigMemroy系列文章--11. BigMemory中的SizeOf问题

    转载请注明出处哈:http://carlosfu.iteye.com/blog/2237511  感谢博主:hot66hot.iteye.com/  一:BigMemory如何使用DirectMemo ...

  4. 将输出结果以json类型打印在控制台上_系列文章:Kubernetes中日志的正确输出姿势...

    前言 上一期主要和大家介绍从全局维度考虑如何去构建K8s中的日志系统,本期我们从实践角度出发来一步步构建K8s中的日志监控体系.构建日志系统的第一步是如何去产生这些日志,而这也往往是最繁杂最困难的一步 ...

  5. Qt系列文章010-Qt容器类介绍

    1 前言    前面已经详细阐述了Qt 中QtGlobal 包含的常用数据类型和方法还有一些宏定义,因为篇幅的问题,所以做了上下两章来讲.方便各位消化和耐看!那么今天这章主要就是讲解Qt 独有的迭代器 ...

  6. Qt系列文章之二十五(使用QAudiolnput获取音频输入)

    文章目录 前言 效果图 QAudioInput获取音频输入功能概述 程序主窗口定义与初始化 音频输入设备支持的格式 开始音频输入 流设备MineDisplayDevice的功能实现 源码获取 前言   ...

  7. Carlosfu技术系列文章总目录

    转载请注明出处哈:http://carlosfu.iteye.com/blog/2240426   刚看了一下这个账号是2009年注册的,当时可能是为了下载javaeye的周刊吧,后来12年开始工作时 ...

  8. Python编程思想【系列文章】

    <Python编程思想>专栏 本系列文章持续更新中....... 李宁老师已经在「极客起源」 微信公众号推出<Python编程思想>电子书,囊括了Python的核心技术,以及P ...

  9. 《Qt 数据库详解》博客系列文章

    本文章原创于www.yafeilinux.com 转载请注明出处. 由于该系列文章图床都挂了,特下载原文博客的word版. 详细博客请点附件下载. 21-Qt数据库(一)简介 22-Qt数据库(二)添 ...

  10. C语言笔记系列文章 索引目录表(持续更新中......)

    前言: 都快大三了,想起大一的时候学C语言,什么都不懂.由于对语言不是很了解,也就没有认真学习.其实C语言在计算机行业中还是比较重要的一门基础课程.虽然现在的开发基本不会用C,但它是母语这是毋庸置疑的 ...

最新文章

  1. C++调用matlab char16_t 重复定义
  2. 城市轨道交通运营票务管理论文_城市轨道交通票务组织管理论文
  3. googlehelper手机版ios_二次元漫画控iOS苹果手机版下载v1.0.0下载|免费二次元漫画控iOS苹果手机版下载绿色版...
  4. Zabbix Server安装
  5. 树的遍历和图的遍历的异同
  6. mpeg4视频中,I帧、p帧、B帧的判定
  7. JDK8新特性-Lambda表达式查找
  8. 在复杂度o(n)的要求下找到n个数的中位数(n为奇数)_啊这,一道找中位数的算法题把东哥整不会了…...
  9. 用linux制作Mac OS U盘启动
  10. 添加三个字母即可免费下载百度文库的文档
  11. fortran程序设计2011年注册电气工程师基础考试大纲3
  12. mac怎么用ntfs硬盘 NTFS移动硬盘怎么在mac上使用
  13. lzg_ad:XPE镜像文件部署详解
  14. message——UVM
  15. 使用 CMake 解决编译出来的 so 文件过大的问题
  16. 四种利用js导出Excel的方法(兼容IE6+、主流浏览器、支持复杂表头和合并单元格)
  17. pandas基础操作大全之数据合并
  18. Bandicam FPS 帧率模式 VFR(可变帧率) 和 CFR (恒定帧率) 到底是什么鬼?
  19. 百度手机助手存储资源优化实践
  20. 招聘管理系统简单设计

热门文章

  1. 用AI让逝去的亲人照片动起来后,数百万网友泪目:原来思念这么重
  2. windows2008 RD授权管理器下空的没服务器(授权管理器无法链接到许可证服务器)问题处理...
  3. 工业过程建模与先进控制(十)MPC的MATLAB命令
  4. 苹果系统中英文输入法切换_苹果输入法怎么切换_苹果系统如何切换输入法-win7之家...
  5. kingbase 数据库初始化失败
  6. 安装mantis 2.14
  7. Python 网页下载文件
  8. python星号怎么输入_python 星号*使用方法
  9. torch.Generator 随机数生成器
  10. android 调用webservice实现手机号码归属地查询