Question

I use a QAbstractItemModel to represent a tree model (of up to a few hounded items). The data itself is dynamic, at any time nodes may appear or disappear, values (or other roles) may change.

Making changes to the model is easy; I am wondering how to efficiently emit the signals in order to notify a QTreeView of the changes (most of it's nodes are collapsed).

At any given time multiple changes may occur simultaneously (row insertions and/or deletions).

  1. Using beginInsertRows / endInsertRows / beginRemoveRows / endRemoveRows - shouldn't there be a method to notify the view of multiple changes?
  2. In terms of performance, what would be the best strategy? For example, starting at the leaves and going up to the root / for each node - bottom to top (vs top to botton) / deletions before insertions / etc.
  3. Would beginResetModel / endResetModel necessarily be less efficient?
  4. Is there any advantage for using QStandardItemModel? (for this specific case).
Was it helpful?

Solution

  1. Yes. The method of notifying everyone of disjoint removals/additions is to emit multiple signals. It would, in most cases, cause more overhead to pass some complex data structure instead of just the parent index and delimiting row/column indices.

  2. You should only notify about the removal/addition of an item closes to the root. It makes no sense to notify about removal of children if their parent is subsequently to vanish. The notification about the parent means that the children, obviously, aren't there anymore.

  3. It's not only about efficiency, but also about state. A model reset resets the view state. The view, upon receiving a reset, can't but assume that it got an entirely new, unrelated model - so you lose selections, expanded/collapsed state, etc. There's no way for a view to act any other way in face of a reset. Doing otherwise would require a view to keep its own copy of the model's contents.

    Since a model reset implies relayout of all of the items, and it can be a very expensive thing to do, you should only do it if, in aggregate, more than 50% of the original items are changed (removed/replaced/added).

  4. No, there is no advantage, and unless you store your data as variants, using QStandardItemModel will always end up with larger memory overhead. It is a convenience class that makes sense if it fits your needs exactly. In fact, if you're not careful about how you use it, it will work worse.

    For example, if you remove an item by iterating depth-first and removing the farthest children first, then the QStandardItemModel can't foresee the future - namely, that you really want to remove the common ancestor of all of those children, and will emit a lot of change events unnecessarily. You can deal with it properly in your own model, or if you simply remove the common parent without touching the children - as they will be implicitly removed, too.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top