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

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

点击获取Qt Widget组件下载(Q技术交流:166830288)

树项类定义

该类提供包含多个数据的简单项,包括有关其父项和子项的信息:TreeItem

class TreeItem
{
public:
explicit TreeItem(const QList<QVariant> &data, TreeItem *parent = nullptr);
~TreeItem();

TreeItem *child(int number);
int childCount() const;
int columnCount() const;
QVariant data(int column) const;
bool insertChildren(int position, int count, int columns);
bool insertColumns(int position, int columns);
TreeItem *parent();
bool removeChildren(int position, int count);
bool removeColumns(int position, int columns);
int childNumber() const;
bool setData(int column, const QVariant &value);

private:
QList<TreeItem *> childItems;
QList<QVariant> itemData;
TreeItem *parentItem;
};

我们将 API 设计为类似于 QAbstractItemModel 提供的 API,为每个项目提供返回信息列数、读取和写入数据以及插入和删除列的函数。但是,我们通过提供处理“子”而不是“行”的函数来明确项目之间的关系。

每个项都包含一个指向子项的指针列表、一个指向其父项的指针,以及一个 QVariant 对象列表,这些对象对应于模型中给定行的列中保存的信息。

树项类实现

每个都由数据列表和一个可选的父项构造:TreeItem

TreeItem::TreeItem(const QList<QVariant> &data, TreeItem *parent)
: itemData(data), parentItem(parent)
{}

最初,每个项目都没有子项。这些函数使用后面介绍的函数添加到项的内部成员中。childItemsinsertChildren()

析构函数确保在删除项本身时删除添加到项的每个子项:

TreeItem::~TreeItem()
{
qDeleteAll(childItems);
}

由于每个项目都存储指向其父项的指针,因此该函数很简单:parent()

TreeItem *TreeItem::parent()
{
return parentItem;
}

三个函数提供有关项的子项的信息。 从内部子项列表中返回特定的子项:child()

TreeItem *TreeItem::child(int number)
{
if (number < 0 || number >= childItems.size())
return nullptr;
return childItems.at(number);
}

该函数返回子项的总数:childCount()

int TreeItem::childCount() const
{
return childItems.count();
}

该函数用于确定子项在其父项的子项列表中的索引。它直接访问父级的成员以获取此信息:childNumber()childItems

int TreeItem::childNumber() const
{
if (parentItem)
return parentItem->childItems.indexOf(const_cast<TreeItem*>(this));
return 0;
}

根项没有父项;对于此项,我们返回零以与其他项保持一致。

该函数仅返回 QVariant 对象内部列表中的元素数:columnCount()itemData

int TreeItem::columnCount() const
{
return itemData.count();
}

使用函数检索数据,该函数访问列表中的相应元素:data()itemData

QVariant TreeItem::data(int column) const
{
if (column < 0 || column >= itemData.size())
return QVariant();
return itemData.at(column);
}

数据是使用函数设置的,该函数仅将有效列表索引的值存储在列表中,对应于模型中的列值:setData()itemData

bool TreeItem::setData(int column, const QVariant &value)
{
if (column < 0 || column >= itemData.size())
return false;

itemData[column] = value;
return true;
}

为了使模型的实现更容易,我们返回 true 以指示数据已成功设置。

可编辑模型通常需要调整大小,以便插入和删除行和列。在模型中给定模型索引下插入行会导致在相应的项中插入新的子项,由以下函数处理:insertChildren()

bool TreeItem::insertChildren(int position, int count, int columns)
{
if (position < 0 || position > childItems.size())
return false;

for (int row = 0; row < count; ++row) {
QList<QVariant> data(columns);
TreeItem *item = new TreeItem(data, this);
childItems.insert(position, item);
}

return true;
}

这可确保使用所需列数创建新项,并将其插入到内部列表中的有效位置。使用以下函数删除项目:childItemsremoveChildren()

bool TreeItem::removeChildren(int position, int count)
{
if (position < 0 || position + count > childItems.size())
return false;

for (int row = 0; row < count; ++row)
delete childItems.takeAt(position);

return true;
}

如上所述,用于插入和删除列的函数与用于插入和删除子项的函数使用方式不同,因为它们应该在树中的每个项上调用。我们通过在项目的每个子项上递归调用此函数来实现这一点:

bool TreeItem::insertColumns(int position, int columns)
{
if (position < 0 || position > itemData.size())
return false;

for (int column = 0; column < columns; ++column)
itemData.insert(position, QVariant());

for (TreeItem *child : std::as_const(childItems))
child->insertColumns(position, columns);

return true;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值