My approach was to save the list of expanded items (as pointers) and when restoring, set the items in this list as expanded.
In order to use the code below, you may need to replace TreeItem*
to a constant pointer to your object (that doesn't change after a refresh).
*.h
:
protected slots:
void restoreTreeViewState();
void saveTreeViewState();
protected:
QList<TargetObject*> expandedTreeViewItems;
*.cpp
:
connect(view->model(), SIGNAL(modelAboutToBeReset()), this, SLOT(saveTreeViewState()));
connect(view->model(), SIGNAL(modelReset()), this, SLOT(restoreTreeViewState()));
...
void iterateTreeView(const QModelIndex & index, const QAbstractItemModel * model,
const std::function<void(const QModelIndex&, int)> & fun,
int depth=0)
{
if (index.isValid())
fun(index, depth);
if (!model->hasChildren(index) || (index.flags() & Qt::ItemNeverHasChildren)) 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)
iterateTreeView(model->index(i, j, index), model, fun, depth+1);
}
void MainWindow::saveTreeViewState()
{
expandedTreeViewItems.clear();
iterateTreeView(view->rootIndex(), view->model(), [&](const QModelIndex& index, int depth){
if (!view->isExpanded(index))
{
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if(item && item->getTarget())
expandedTreeViewItems.append(item->getTarget());
}
});
}
void MainWindow::restoreTreeViewState()
{
iterateTreeView(view->rootIndex(), view->model(), [&](const QModelIndex& index, int depth){
TreeItem *item = static_cast<TreeItem*>(index.internalPointer());
if(item && item->getTarget())
view->setExpanded(index, expandedTreeViewItems.contains(item->getTarget()));
});
}
I think this implementation gives extra flexibility compared to some of the others here. At least, I could not make it work with my custom model.
If you want to keep new items expanded, change the code to save the collapsed items instead.