当前位置: 首页 > news >正文

Qt学习之路(46): 自定义model之二

版权声明: 原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 、作者信息和本声明。否则将追究法律责任。 http://devbean.blog.51cto.com/448512/267972
前 面的例子已经比较清楚的给出了自定义model的方法,就是要覆盖我们所需要的那几个函数就可以了。但是,前面的例子仅仅是简单的展示数据,也就是说数据 时只读的。那么,如何能做到读写数据呢?那就要来看进来的例子了。这个例子也是来自C++GUI Programming with Qt 4, 2nd Edition这本书的。
还是先来看代码吧:
citymodel.h
class CityModel : public QAbstractTableModel
{
Q_OBJECT

public :
CityModel(QObject *parent = 0);

void setCities( const QStringList &cityNames);
int rowCount( const QModelIndex &parent) const ;
int columnCount( const QModelIndex &parent) const ;
QVariant data( const QModelIndex &index, int role) const ;
bool setData( const QModelIndex &index, const QVariant &value, int role);
QVariant headerData( int section, Qt::Orientation orientation, int role) const ;
Qt::ItemFlags flags( const QModelIndex &index) const ;

private :
int offsetOf( int row, int column) const ;

QStringList cities;
QVector< int > distances;
};
citymodel.cpp
CityModel::CityModel(QObject *parent)
: QAbstractTableModel(parent)
{
}

int CityModel::rowCount( const QModelIndex & parent) const
{
return cities.count();
}

int CityModel::columnCount( const QModelIndex & parent) const
{
return cities.count();
}

QVariant CityModel::data( const QModelIndex &index, int role) const
{
if (!index.isValid()) {
return QVariant();
}

if (role == Qt::TextAlignmentRole) {
return int (Qt::AlignRight | Qt::AlignVCenter);
} else if (role == Qt::DisplayRole) {
if (index.row() == index.column()) {
return 0;
}
int offset = offsetOf(index.row(), index.column());
return distances[offset];
}
return QVariant();
}

QVariant CityModel::headerData( int section, Qt::Orientation orientation, int role) const
{
if (role == Qt::DisplayRole) {
return cities[section];
}
return QVariant();
}

bool CityModel::setData( const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && index.row() != index.column() && role == Qt::EditRole) {
int offset = offsetOf(index.row(), index.column());
distances[offset] = value.toInt();

QModelIndex transposedIndex = createIndex(index.column(), index.row());
emit dataChanged(index, index);
emit dataChanged(transposedIndex, transposedIndex);
return true ;
}
return false ;
}

Qt::ItemFlags CityModel::flags( const QModelIndex &index) const
{
Qt::ItemFlags flags = QAbstractItemModel::flags(index);
if (index.row() != index.column()) {
flags |= Qt::ItemIsEditable;
}
return flags;
}

void CityModel::setCities( const QStringList &cityNames)
{
cities = cityNames;
distances.resize(cities.count() * (cities.count() - 1) / 2);
distances.fill(0);
reset();
}

int CityModel::offsetOf( int row, int column) const
{
if (row < column) {
qSwap(row, column);
}
return (row * (row - 1) / 2) + column;
}
代码很长,但实际上和前面我们的那个例子非常相似。这个model也是用于table的,因此还是继承了 QAbstractTableModel。CityModel内部有两个数据源:一个QStringList类型的对象,一个 QVector&lt;int>类型的对象。前者用于保存城市的名字,需要用户显示的给出;后者是model内部维护的一个存放int的向 量。这个CityModel就是要在table中显示两个城市之间的距离。同前面的例子一样,如果我们要把所有的数据都保存下来,显然会造成数据的冗余: 城市A到城市B的距离同城市B到城市A的距离是一样的!因此我们还是自定义一个model。同样这个CityModel有个简单的空构造函 数,rowCount()和columnCount()函数也是返回list的长度。data()函数根据role的不同返回不同的值。由于在table 中坐标是由row和column给出的,因此需要有一个二维坐标到一维坐标的转换,这就是offsetOf()函数的作用。我们把主要精力放在 setData()函数上面。
bool CityModel::setData( const QModelIndex &index, const QVariant &value, int role)
{
if (index.isValid() && index.row() != index.column() && role == Qt::EditRole) {
int offset = offsetOf(index.row(), index.column());
distances[offset] = value.toInt();

QModelIndex transposedIndex = createIndex(index.column(), index.row());
emit dataChanged(index, index);
emit dataChanged(transposedIndex, transposedIndex);
return true ;
}
return false ;
}
这个函数在用户编辑数据时会自动调用。也就是说,这时我们的数据已经不是只读的了。函数开始是一个长长的判断:index要是合法 的;index的row和column不相等,也就是说两个城市是不同的;数据想的role是Qt::EditRole。如果满足了这三个条件,才会执行 下面的操作。首先,由row和column坐标定位到表中的数据项在vector中的位置。然后用户新修改的数据被作为参数value传入,所以我们要把 这个参数赋值给distances。createIndex()函数根据column和row值生成一个QModelIndex对象。请注意这里的顺 序:row和column是颠倒的!这就把坐标为(row, column)的点关于主对角线对称的那个点(column, row)的index找到了。还记得我们的需求吗?当我们修改了一个数据时,对应的数据也要被修改,这就是这个功能的实现。我们需要emit dataChanged()信号,这个信号接收两个参数:一个是被修改的数据的左上角的坐标,一个是被修改的数据的右下角的坐标。为什么会有两个坐标呢? 因此我们修改的数据不一定只是一个。像这里,我们只修改了一个数据,因此这两个值是相同的。数据更新了,我们用这个信号通知view刷新,这样就可以显示 新的数据了。最后,如果函数数据修改成功就返回true,否则返回false。
最后,我们在main()函数中显示出来这个model:
int main( int argc, char *argv[])
{
QApplication a(argc, argv);
QStringList cities;
cities << "Arvika" << "Boden" << "Eskilstuna" << "Falun" ;

CityModel cityModel;
cityModel.setCities(cities);

QTableView tableView;
tableView.setModel(&cityModel);
tableView.setAlternatingRowColors( true );
tableView.setWindowTitle(QObject::tr( "Cities" ));
tableView.show();
return a.exec();
}
这样,我们就把这个model做完了。最后来看看效果吧!
2010-1-19

本文出自 “豆子空间 ” 博客,请务必保留此出处http://devbean.blog.51cto.com/448512/267972

相关文章:

  • 解决EntityFramework数据库无法自动迁移解决方法
  • Qt学习之路(45): 自定义model之一
  • 编译原理-词法分析器(DFA,C语言描述,可分析C/C++词法)
  • SQL 表操作
  • Qt学习之路(44): QSortFilterProxyModel
  • UIimage图片在程序Documents目录下的存取
  • Qt学习之路(43): QDirModel
  • java “==”和“ equals”以及instanceof的区别
  • Qt学习之路(42): QStringListModel
  • The Clocks
  • 发布app store流程
  • Qt学习之路(41): QTableWidget
  • Qt学习之路(40): QTreeWidget
  • 配置EM遇到的问题
  • Qt学习之路(38): model-view架构
  • [译] 怎样写一个基础的编译器
  • 【跃迁之路】【641天】程序员高效学习方法论探索系列(实验阶段398-2018.11.14)...
  • crontab执行失败的多种原因
  • HTTP--网络协议分层,http历史(二)
  • JavaScript 是如何工作的:WebRTC 和对等网络的机制!
  • Linux学习笔记6-使用fdisk进行磁盘管理
  • python3 使用 asyncio 代替线程
  • Redis字符串类型内部编码剖析
  • 简单基于spring的redis配置(单机和集群模式)
  • 蓝海存储开关机注意事项总结
  • 前端代码风格自动化系列(二)之Commitlint
  • 如何学习JavaEE,项目又该如何做?
  • 优秀架构师必须掌握的架构思维
  • 职业生涯 一个六年开发经验的女程序员的心声。
  • mysql 慢查询分析工具:pt-query-digest 在mac 上的安装使用 ...
  • 如何通过报表单元格右键控制报表跳转到不同链接地址 ...
  • ​Distil-Whisper:比Whisper快6倍,体积小50%的语音识别模型
  • $$$$GB2312-80区位编码表$$$$
  • (1)STL算法之遍历容器
  • (20)目标检测算法之YOLOv5计算预选框、详解anchor计算
  • (react踩过的坑)Antd Select(设置了labelInValue)在FormItem中initialValue的问题
  • (vue)页面文件上传获取:action地址
  • (二)学习JVM —— 垃圾回收机制
  • (附程序)AD采集中的10种经典软件滤波程序优缺点分析
  • (三)elasticsearch 源码之启动流程分析
  • (三分钟了解debug)SLAM研究方向-Debug总结
  • (五)IO流之ByteArrayInput/OutputStream
  • (一)eclipse Dynamic web project 工程目录以及文件路径问题
  • (转)Google的Objective-C编码规范
  • (转)Java socket中关闭IO流后,发生什么事?(以关闭输出流为例) .
  • (最完美)小米手机6X的Usb调试模式在哪里打开的流程
  • * CIL library *(* CIL module *) : error LNK2005: _DllMain@12 already defined in mfcs120u.lib(dllmodu
  • .net 生成二级域名
  • .net 使用$.ajax实现从前台调用后台方法(包含静态方法和非静态方法调用)
  • @property @synthesize @dynamic 及相关属性作用探究
  • [100天算法】-每个元音包含偶数次的最长子字符串(day 53)
  • [100天算法】-实现 strStr()(day 52)
  • [ACM] hdu 1201 18岁生日
  • [Angular 基础] - 自定义指令,深入学习 directive
  • [APUE]进程关系(下)