彩票走势图

界面开发框架Qt新手入门教程:可编辑树模型的示例(三)

翻译|使用教程|编辑:周思宇|2023-05-26 11:55:38.023|阅读 96 次

概述:本章讲述Qt可编辑树模型的示例(三),欢迎阅读~

# 慧都年终大促·界面/图表报表/文档/IDE等千款热门软控件火热促销中 >>

Qt 是目前最先进、最完整的跨平台C++开发工具。它不仅完全实现了一次编写,所有平台无差别运行,更提供了几乎所有开发过程中需要用到的工具。如今,Qt已被运用于超过70个行业、数千家企业,支持数百万设备及应用。

The Qt Company是Digia Plc旗下的全资子公司。负责所有Qt活动,包括产品开发,商业和开源授权模式以及在开放管理模式下的Qt工程。其许可、支持和服务能力能够和开发者紧密合作以确保他们的Qt项目准时部署,不超预算并拥有竞争优势。

Qt技术交流群:166830288

TreeModel 类定义

该TreeModel类提供了一个实现QAbstractItemModel类,为可以编辑和调整大小的模型公开必要的接口。

class TreeModel : public QAbstractItemModel
{
Q_OBJECT

public:
TreeModel(const QStringList &headers, const QString &data,
QObject *parent = nullptr);
~TreeModel();

构造函数和析构函数是特定于这个模型的。

QVariant data(const QModelIndex &index, int role) const override;
QVariant headerData(int section, Qt::Orientation orientation,
int role = Qt::DisplayRole) const override;

QModelIndex index(int row, int column,
const QModelIndex &parent = QModelIndex()) const override;
QModelIndex parent(const QModelIndex &index) const override;

int rowCount(const QModelIndex &parent = QModelIndex()) const override;
int columnCount(const QModelIndex &parent = QModelIndex()) const override;

只读树模型只需要提供以上功能即可。以下公共函数提供对编辑和调整大小的支持:

Qt::ItemFlags flags(const QModelIndex &index) const override;
bool setData(const QModelIndex &index, const QVariant &value,
int role = Qt::EditRole) override;
bool setHeaderData(int section, Qt::Orientation orientation,
const QVariant &value, int role = Qt::EditRole) override;

bool insertColumns(int position, int columns,
const QModelIndex &parent = QModelIndex()) override;
bool removeColumns(int position, int columns,
const QModelIndex &parent = QModelIndex()) override;
bool insertRows(int position, int rows,
const QModelIndex &parent = QModelIndex()) override;
bool removeRows(int position, int rows,
const QModelIndex &parent = QModelIndex()) override;

private:
void setupModelData(const QStringList &lines, TreeItem *parent);
TreeItem *getItem(const QModelIndex &index) const;

TreeItem *rootItem;
};

为了简化这个示例,模型公开的数据通过模型的setupModelData()函数组织到一个数据结构中。许多现实世界的模型根本不会处理原始数据,而只是使用现有的数据结构或库API。

TreeModel 类实现

构造函数创建一个根项并使用提供的标头数据对其进行初始化:

TreeModel::TreeModel(const QStringList &headers, const QString &data, QObject *parent)
: QAbstractItemModel(parent)
{
QList<QVariant> rootData;
for (const QString &header : headers)
rootData << header;

rootItem = new TreeItem(rootData);
setupModelData(data.split('\n'), rootItem);
}

调用内部的setupModelData()函数,将提供的文本数据转换为可以与模型一起使用的数据结构。其他模型可以使用现成的数据结构进行初始化,或者使用维护自己数据的库中的API。

析构函数只需删除根项,这将导致递归删除所有子项。

TreeModel::~TreeModel()
{
delete rootItem;
}

由于模型到其他模型/视图组件的接口是基于模型索引的,并且由于内部数据结构是基于项的,因此模型实现的许多函数需要能够将任何给定的模型索引转换为相应的项。为了方便和一致性,我们定义了一个getItem()函数来执行这个重复的任务:

TreeItem *TreeModel::getItem(const QModelIndex &index) const
{
if (index.isValid()) {
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if (item)
return item;
}
return rootItem;
}

传递给此函数的每个模型索引都应对应于内存中的有效项目。如果索引无效,或其内部指针未指向有效项,则返回根项。

该模型的rowCount()实现很简单:首先使用函数getItem()获取相关项;然后返回它所包含的子项的个数:

int TreeModel::rowCount(const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() > 0)
return 0;

const TreeItem *parentItem = getItem(parent);

return parentItem ? parentItem->childCount() : 0;
}

相比之下,columnCount()实现不需要查找特定项目,因为所有项目都被定义为具有相同数量的与其关联的列。

int TreeModel::columnCount(const QModelIndex &parent) const
{
Q_UNUSED(parent);
return rootItem->columnCount();
}

因此,可以直接从根项中获取列数。

为了使项目能够被编辑和选择,需要实现flags()函数,以便它返回标志的组合,包括Qt::ItemIsEditable和Qt::ItemIsSelectable标志以及Qt::ItemIsEnabled。

Qt::ItemFlags TreeModel::flags(const QModelIndex &index) const
{
if (!index.isValid())
return Qt::NoItemFlags;

return Qt::ItemIsEditable | QAbstractItemModel::flags(index);
}

该模型需要能够生成模型索引,以允许其他组件请求有关其结构的数据和信息。该任务由index()函数执行,该函数用于获取与给定父项的子项对应的模型索引:

QModelIndex TreeModel::index(int row, int column, const QModelIndex &parent) const
{
if (parent.isValid() && parent.column() != 0)
return QModelIndex();

在此模型中,如果父索引无效(对应于根项)或列号为零,我们仅返回子项的模型索引。

我们使用自定义getItem()函数来获取与所提供的模型索引对应的TreeItem实例,并请求与指定行对应的其子项。

TreeItem *parentItem = getItem(parent);
if (!parentItem)
return QModelIndex();

TreeItem *childItem = parentItem->child(row);
if (childItem)
return createIndex(row, column, childItem);
return QModelIndex();
}

由于每项都包含一整行数据的信息,因此我们创建一个模型索引,通过调用createIndex()来唯一地标识它,方法是使用行号和列号以及指向该项目的指针。在data()函数中,我们将使用项目指针和列号来访问与模型索引相关的数据;在此模型中,不需要行号来标识数据。

parent()函数通过查找给定模型索引的相应项,使用它的parent()函数获得它的父项,然后创建一个模型索引来表示父项,从而为项的父项提供模型索引。(如图所示)。

QModelIndex TreeModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();

TreeItem *childItem = getItem(index);
TreeItem *parentItem = childItem ? childItem->parent() : nullptr;

if (parentItem == rootItem || !parentItem)
return QModelIndex();

return createIndex(parentItem->childNumber(), 0, parentItem);
}

没有父项的项(包括根项)通过返回空模型索引来处理。否则,将像index()函数一样创建并返回一个模型索引,并使用合适的行号,但列号为零,与index()实现中使用的方案一致。


欢迎下载|体验更多Qt产品

获取更多信息请咨询  ;Qt技术交流群:166830288


标签:

本站文章除注明转载外,均为本站原创或翻译。欢迎任何形式的转载,但请务必注明出处、不得修改原文相关链接,如果存在内容上的异议请邮件反馈至chenjj@pclwef.cn


为你推荐

  • 推荐视频
  • 推荐活动
  • 推荐产品
  • 推荐文章
  • 慧都慧问
扫码咨询


添加微信 立即咨询

电话咨询

客服热线
023-68661681

TOP