Qt--自定义Model
众所周知,Qt提供了一套Model/View框架供开发者使用,Model用来提供数据, View则用来提供视觉层的显示。实际上这是一套遵循MVC设计模式的GUI框架,因为Qt还提供了默认的Delegate作为Controller来作为控制器。

MVC的好处这里就不多说了,为了开发者使用方便,Qt还提供了基于项(Item)的Model/View实现----QXxxWidget(QTableWidget、QListWidget等),对于一些简单的应用场景,这已经足够了并且使用起来非常方便。这里我们简单介绍下如何使用自定义的数据模型,来满足各种花式的要求。
1. 选择合适的Model继承
1.1 标准数据模型
Qt实现了4类标准数据模型供我们在不同的场景下使用:
- QStringListModel:存储字符串列表。
- QStandardItemModel:存储树状结构的任意数据。
- QFileSystemModel:存储本地文件系统上的文件和目录信息。
- QSqlQueryModel、QSqlRelationalTableModel、QSqlTableModel:存储关系型数据库中的数据。
如果使用情况和上述情况之一比较相似,则可以考虑继承对应的模型类,并重新实现少数虚函数。
1.2 抽象数据模型
抽象数据模型有3类:
- QAbstractItemModel:项模型,这是所有数据模型的基类。
- QAbstractListModel:列表模型,结合QListView使用最合适。
- QAbstractTableModel:表模型,结合QTableView使用最合适。
2. 继承抽象模型
Qt官方提供了完善的文档来帮助开发者来自定义模型类。根据官网,子类化模型需要开发者实现的功能(即需要重新实现的虚函数)按功能来分可以分为三类:
- 项数据处理:这又可以分为三类----只读访问、可编辑、调整大小。
- 导航和下标创建。
- 拖拽和MIME类型处理。
我们只需要按照自己的功能需求来实现其中的一些虚函数。
3. 实现一个自定义模型
这里我们来实现一个自定义模型,并在QTableView中使用它,因此我们选择继承QAbstractTableModel,这样我们需要做的改动最少。但使用QTableModel并不意味着我们的数据结构就是Table状的,例如下面的例子中我们根本不需要内部数据结构。
下面我们要实现这样一个数据模型:
- 内部不存储数据结构。
- 表中的每一个单元获得的数据是整型,并且值为列下标的平方。
- 模型中的数据为只读。
3.1 实现CustomeModel
该模型继承自QAbstractTableModel,作为只读模型,我们只需要实现以下几个虚函数:
virtual Qt::ItemFlags flags(const QModelIndex &index) const;
virtual QVariant data(const QModelIndex &index, int role) const;
virtual QVariant headerData(int section, Qt::Orientation orientation, int role) const;
virtual int rowCount(const QModelIndex &parent) const;
virtual int columnCount(const QModelIndex &parent) const;
data()函数与项数据有关,这里数据有好几种角色(role),最基本的就是Qt::DisplayRole,这里为了实现居中效果,我们还处理了Qt::TextAlignmentRole角色:
QVariant MyTableModel::data(const QModelIndex &index, int role) const
{
if (role == Qt::DisplayRole) {
return index.column() * index.column();
}
if (role == Qt::TextAlignmentRole) {
return Qt::AlignCenter;
}
return QVariant();
}
headerData()函数提供表头数据,包括两个方向(垂直、水平)的表头。同样,这里的数据也有好几种角色,我们只处理Qt::DisplayRole:
QVariant MyTableModel::headerData(int section, Qt::Orientation orientation, int role) const
{
if (orientation == Qt::Vertical) {
if (role == Qt::DisplayRole) return QVariant("row:" + QString::number(section));
else return QVariant();
}
if (orientation == Qt::Horizontal) {
if (role == Qt::DisplayRole) return QVariant("column:" + QString::number(section));
else return QVariant();
}
}
rowCount()和columnCount()返回数据模父下标(QModelIndex)的行和列数量,这里我们要判别下标是否有效:因为整个表模型的父下标为无效下标,我们返回表模型的行列数量;当下标有效时,我们返回的是父下标指向处的子表的行列:
// if `parent` is invalid, return the whole table row count!
// else return the children row count of the `parent`
int MyTableModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid())
return 0;
else
return 10;
}
3.2 运行结果

完整代码见此处。
Qt--自定义Model的更多相关文章
- Qt自定义model
前面我们说了Qt提供的几个预定义model.但是,面对变化万千的需求,那几个model是远远不能满足我们的需要的.另外,对于Qt这种框架来说,model的选择首先要能满足绝大多数功能的需要,这就是说, ...
- Qt 自定义model实现文件系统的文件名排序(重定义sort函数即可。忽然开窍了:其实捕捉点击Header事件,内部重排序,全部刷新显示即可)
前段时间,需要做一个功能是要做文件系统的排序的功能.由于是自己写的model, 自己定义的数据结构.最初的想法只有一个自己去实现文件夹跟文件名的排序算法,不过感觉比较费时间.后来想到的是QFileSy ...
- Qt 自定义model实现文件系统的文件名排序
前段时间,需要做一个功能是要做文件系统的排序的功能.由于是自己写的model, 自己定义的数据结构.最初的想法只有一个自己去实现文件夹跟文件名的排序算法,不过感觉比较费时间.后来想到的是QFileSy ...
- QT内省机制、自定义Model、数据库
本文将介绍自定义Model过程中数据库数据源的获取方法,我使用过以下三种方式获取数据库数据源: 创建 存储对应数据库所有字段的 结构体,将结构体置于容器中返回,然后根据索引值(QModelIndex) ...
- Qt学习之路(45): 自定义model之一
前面我们说了Qt提供的几个预定义model.但是,面对变化万千的需求,那几个model是远远不能满足我们的需要的.另外,对于Qt这种框架来说,model的选择首先要能满足绝大多数功能的需要,这就是说, ...
- Qt之如何自定义model
Qt之如何自定义model https://blog.csdn.net/wei375653972/article/details/86592209
- Undo/Redo for Qt Tree Model
Undo/Redo for Qt Tree Model eryar@163.com Abstract. Qt contains a set of item view classes that use ...
- 浅析在QtWidget中自定义Model
Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...
- 浅析在QtWidget中自定义Model(beginInsertRows()和endInsertRows()是空架子,类似于一种信号,用来通知底层)
Qt 4推出了一组新的item view类,它们使用model/view结构来管理数据与表示层的关系.这种结构带来的功能上的分离给了开发人员更大的弹性来定制数据项的表示,它也提供一个标准的model接 ...
- PyQt学习随笔:Qt中Model/View中的怎么构造View匹配的Model
老猿Python博文目录 老猿Python博客地址 在<PyQt学习随笔:Qt中Model/View相关的主要类及继承关系>介绍了Model/View架构的主要类,在实际使用时,view相 ...
随机推荐
- 24. leetcode 409. Longest Palindrome
409. Longest Palindrome Given a string which consists of lowercase or uppercase letters, find the le ...
- python pygame--倒计时
import pygame,sys,time,datetime class decTime(object): #将秒转化为时分秒 def __init__(self,totalTime): self. ...
- 带有WS-Security验证的webservice
示例用的是spring+CXF来配置webservice 首先是web.xml配置,将spring,CXF的配置文件加载进去,由于我客户端跟服务端在同一个工程里面,所以配置文件在一块. <con ...
- Python查询SQLserver数据库备份(抛砖引玉)
通过python pymssql直接访问SQLserver数据库,查找其数据库mode,这个脚本具有很强的抛砖引玉特性: 1.可以巡检多台多数据库服务器 2.query内容可以多样化,譬如查询死锁.连 ...
- 小米wifi
场景:把小米wifi插主机上,作为热点发射器:然后使用手机搜索到这个热点,建立wifi连接 驱动:当"把小米wifi插主机上"的时候,主机可能无法识别这个设备,所以需要前往官网下载驱动 下载地址:ht ...
- python学习之字符串(下)
----------------------------------------------实际应用中的其他常见的字符串方法 >>>line = "the knights ...
- C++11 中值得关注的几大变化(网摘)
C++11 中值得关注的几大变化(详解) 原文出处:[陈皓 coolshell] 源文章来自前C++标准委员会的 Danny Kalev 的 The Biggest Changes in C++11 ...
- 来杯咖啡看Pecan
Pecan的介绍及安装 文章内容来自官方文档:http://pecan.readthedocs.io/en/latest/quick_start.html Pecan的介绍: Pecan是一个路由对 ...
- mysql 5.7 怎么修改默认密码、随机密码
当你使用 mysql -u root -p 登陆mysql的时候,提示下方要输入密码.而这个密码不是我们刚刚安装mysql时设置的那个密码.而且安装完mysql 生成的随机密码 那么我们在哪里找到这个 ...
- shell流程控制--循环语句
#!/bin/bash ### for循环,数字段形式 echo 'for 循环,数字段形式' ..} do echo $i done ### for 循环,双括号形式 echo 'for 循环,双括 ...