Search code examples
c++qtviewmodelqt5

Storing persistent information about items in view


I've my own view based directly on QAbstractItemView. Generally speaking I need to store some information about particular model's item.

So in my view I have a map from QModelIndex to struct describing partical item. Then I use those data mostly on view's paintEvent.

The problem is, that QModelIndex is not persistent, it may get outdated. So when rows are inserted or removed from model, some QModelIndex may become invalid and I should not relay on them.

How then can I build relation between item in model and some decoration data I use in view?

QPersistentModelIndex seems to be proper tool for such things, however I'm aware of its performance (my model and view may be huge).

Another problem with QPersistentModelIndex is that it probably should not be used as map's key (as it is in my case) as it may (and will) change and make map inconsistent.

I've took a look at Qt's implementation of QTreeView and QListView to see how they deal rows removal/insertion, but it seems they simply drop all the data.

So at this point I cannot see any easy way to solve my problem.


Solution

  • You can safely use a QPersistentModelIndex as a map or hash key. Even if the underlying QModelIndex changes, the "persistent" part ensure that all the QPersistentModelIndex are kept up to date while preserving their identities, i.e operator == and qHash() return consistent values.

    That being said, you should not store data about the index in your view. The data are supposed to be stored by the model. And this seems to be how its done in Qt classes: views are making a lot of calls to QAbstractItemModel::data().

    The only data that I would deem worthy to be stored in the view is "cache data", i.e values that are:

    • not directly provided by the model
    • require heavy computation to be calculated from the model's data
    • specific to the view

    If any of these 3 conditions is not met, my personal preference would be to store the data in the model.


    Edit

    Contrary to my original answer, you cannot safely use QPersistentModelIndex as a QMap key.

    The reason is that QMap uses operator < for inserting and finding data.

    The issue here is that bool QPersistentModelIndex::operator<(const QPersistentModelIndex &other) const is just a proxy to bool QModelIndex::operator<(const QModelIndex &other) const which compares indexes by row and column. This means that the sort order of QPersistentModelIndex is not persistent and will change when indexes are moved in the model.

    However, QMap is not aware that the sort order has changed. And at this point searching a value inside a QMap<QPersistentModelIndex, T> is just as broken as doing binary search on an unsorted array.

    Note that this issue is not limited to QMap, it affects all containers which are based on the ordering of the keys like std::map. However, containers that do not rely on ordering (QHash, std::unordered_map, ...) are not affected.