从标题中可以看到,我使用 QStandardItemModel 来存储树结构。我在 QTreeView 中操作这个结构,然后我需要以这种格式将其保存在数据库中:
|id|Parent|Child |
| 1| |ITEM01|
| 2| 1|ITEM02|
| 3| 2|ITEM03|
| 4| 3|ITEM04|
| 5| 4|ITEM05|
| 6| 5|ITEM06|
| 7| 6|ITEM07|
| 8| 3|ITEM08|
| 9| 3|ITEM09|
|10| 3|ITEM10|
代表这个结构:
ITEM01
║
╠═► ITEM02
║ ║
║ ╚═► ITEM03
║ ║
║ ╠═► ITEM04
║ ║ ║
║ ║ ╚═► ITEM05
║ ║ ║
║ ║ ╚═► ITEM06
║ ║ ║
║ ║ ╚═► ITEM07
║ ║
║ ╠═► ITEM08
║ ╠═► ITEM09
║ ╚═► ITEM10
换句话说,“id”唯一地代表一个节点,“parent”字段是对父节点的引用。根节点是一个空字段。
我的问题是:如何从 QStandardItemModel 获取唯一的 id(int 格式)? 我尝试过 QModelIndex::row() 和 QPersistentModelIndex::row() 但它似乎不是唯一的。
非常感谢。
最简单的方法是当您以某种深度优先顺序遍历树时,从递增计数器分配索引,例如后序 - 左...右,根。
如果您将
id
和 parent
存储为元素的角色,则:
int assignIdsPostorder(QStandardItem * e, int idRole, int parentRole, int counter = 0) {
auto const N = e->rowCount();
for (int i = 0; i < N; ++i)
counter = assignIdsDFS(e->child(i), idRole, parentRole, counter);
if (e->setData(counter, idRole)) counter++;
for (int i = 0; i < N; ++i)
e->child(i)->setData(e->data(idRole), parentRole);
return counter;
}
稍作修改即可将
id
和 parent
存储在单独的列中。
如果索引不需要始终有效,那么您可以通过记忆(缓存)来延迟生成它们。
QStandardItem
派生元素将重新实现data()
以执行部分树遍历以生成其ids
。如果您想避免可能必须在单个 id 查询上注释整个树的情况,则需要根据树的属性调整遍历顺序。
您可以使用
this方法迭代
QAbstractItemModel
。
void iterate(const QModelIndex & index, const QAbstractItemModel * model,
const std::function<void(const QModelIndex&, int)> & fun,
int depth = 0)
{
if (index.isValid())
fun(index, depth);
if ((index.flags() & Qt::ItemNeverHasChildren) || !model->hasChildren(index)) return;
auto rows = model->rowCount(index);
auto cols = model->columnCount(index);
for (int i = 0; i < rows; ++i)
for (int j = 0; j < cols; ++j)
iterate(model->index(i, j, index), model, fun, depth+1);
}
void dumpData(QAbstractItemView * view) {
iterate(view->rootIndex(), view->model(), [](const QModelIndex & idx, int depth){
qDebug() << depth << ":" << idx.row() << "," << idx.column() << "=" << idx.data();
});
}
然后使用
QModelIndex::parent()
获取项目的父项目,最后使用 QModelIndex::internalId()
获取父项目和项目本身的唯一 ID。