写点什么

Qt | 如何创建一个新的模型

作者:YOLO.
  • 2022 年 9 月 07 日
    河北
  • 本文字数:1982 字

    阅读完需:约 7 分钟

Qt | 如何创建一个新的模型

前言:

当要为一个已经存在的数据结构创建一个新的模型时,需要考虑使用那种类型的模型来为数据提供接口。如果数据结构可以表示为项目列表或者表格,那么可以子类化 QAbstractListModel 或者 QAbstractTableModel,在这个的基础上创建属于自己的新模型。如果底层数据结构只能表示为具有层次的树结构,那么就需要子类化 QAbstractItemModel。

创建一个只读模型:

创建一个基于 QStringListModel 类的、简单的、非层次结构的、只读的数据模型。

class StringListModel : public QAbstractListModel{}
复制代码

该模型使用了一个 QStringList 作为内部的数据源,是因为 QAbstractItemModel 本身不存储数据,QAbstractItemModel 仅仅提供一些接口来供视图访问数据。

在定义的模型类中,除了构造函数之外,只需要实现两个函数:rowCount()data()。这里还实现了 headerData() 函数。

  • rowCount()返回模型的行数;

  • data()返回指定模型索引的数据项。

  • headerData()可以在树和表格视图的标头显示一些内容。

因为这里实现的模型时非层次结构的,所以不需要考虑父子关系。但是,如果模型时层次结构的,还需要实现 index()和 parent()函数。

函数实现:

//rowCont()函数int StringListModel::rowCount(QModelIndex &parent){    return stringList.count();}
//data()函数QVariant StringListModel::data(QModelIndex &index, int role){ if(!index.isValid) return QVariant(); if(index.row() == stringList.size()) return QVariant(); if(role == Qt::DiaplayRole) return stringList.at(index.row()); else return QVariant();}
复制代码

当提供的索引是有效的,行号咋字符串列表的大小范围之内,而且需要的角色是支持的角色之一时,返回一个有效的 QVariant。

//headerData()函数QVariant StringListModel::headerData(int section, Qt::Qrientation orientation, int role){    if(role != Qt::DsiplayRole)        return QVariant();    if(orientation == Qt::Horizontal)        return QString("Column %1").arg(section);    else        return QString("Row %1").arg(section);}//这里实现了在标头中显示行号和列号
复制代码

使用:

QStringList list;list << "a" << "b" << "c";StringListModel model(list);//将模型展示在列表视图中QListView listView;listView.setModel(&model);listView.show();//将模型展示在表格视图中QTableView tableView;tableView.setModel(&model);tableView.show();
复制代码

添加编辑功能:

如果想为模型添加编辑功能,需要实现两个函数:flags()和 setData()。flags()函数为模型中的每一个项目返回一个正确的标识来达到检测项目是否可编辑的目的。通过 setData()函数为模型中的项目设置数据。

实现:

Qt::ItemFlags StringListModel::flags(QModelIndex &index){    if(!index.isValid())        return Qt::ItemIsEnabled;    return QAbstractItemModel::flags(index) | Qt::ItemIsEditable;}
bool StringListModel::setData(QModelIndex &index, QVariant &value, int role){ if(index.isValid() && role == Qt::EditRole){ stringList.replace(index.row(), value.toString()); emit dataChanged(index, index); return true; } return false;}
复制代码

当数据被设置后,模型必须发送 dataChanged()信号通知视图,让视图知道数据已经改变了。

插入和删除行:

如果想在模型中实现插入和删除行的功能,需要重新实现 insertRows()和 removeRows()函数。

实现:

  • 因为模型中的行对应着列表中的字符串,所以添加行时指定添加空字符串。

  • 父索引是用来决定在模型的什么位置添加行的。

  • 模型首先要调用 beginInsertRows()函数来告知其他组件指定的行将要发生改变,这个函数指定了将要插入的第一个、最后一个新行的行号,以及它们的父项的模型索引。

  • 当改变玩字符串以后,需要调用 endInsertRows()函数来完成操作,并告知其他组件该模型的大小发生了变化。

bool StringListModel::insetRows(int position, int rows, const QModelIndex &parent){    beginInsertRows(QModelIndex(), position, positon += rows-1);    for(int row = 0; row < rows; ++row){        stringList.inset(position, "");    }    endInsertRows();    return true;}
复制代码

删除行的操作与插入行的操作类似。

bool StringListModel::removeRows(int position, int rows, const QModelIndext &parent){    beginRemoveRows(QModelIndex().position, position, position+rows-1);    for(int row = 0; row < rows; ++row){        stringList.removeAt(positon);    }    endRemoveRows();    return true;}
复制代码

调用:

model.insertRows(3, 2);//在模型第3个数据项后添加2个空数据项model.removeRows(0, 1);//删除模型的第一个数据项
复制代码


发布于: 刚刚阅读数: 6
用户头像

YOLO.

关注

还未添加个人签名 2022.05.06 加入

还未添加个人简介

评论

发布
暂无评论
Qt | 如何创建一个新的模型_qt_YOLO._InfoQ写作社区