PDA

View Full Version : QPersistentModelIndex



coderbob
11th December 2008, 09:26
From the docs on QModelIndex : "Note: Model indexes should be used immediately and then discarded. You should not rely on indexes to remain valid after calling model functions that change the structure of the model or delete items. If you need to keep a model index over time use a QPersistentModelIndex ".

My problem is the interpretation of the word "immediately". Are we talking a single atomic operation? A few calls? Multiple function calls? What about threading issues?

I understand checking if it isValid() before any work to ensure it is safe to use but it leaves me guessing how long it will be valid and if I need to re acquire an index mid function since it is no longer valid.

For me personally the code for Qt is hard to understand so when I look through the source I am not sure I am interpreting it properly. My guess would be that the index would remain valid as long as no data has changed in the model to force it to re optimize itself.

So this leaves me with QPersistentModelIndex. I do not have the source of the information at had to quote right now but I have "read" that using a QPersistentModelIndex comes as a significant overhead cost. That it must be updated any time the model changes to ensure that it is properly positioned.

So I can live with a short life cycle of a QModelIndex and don't really see any problems there other then unsure how long many cycles I can trust it validity.

Now I am going to need a QPersistentModelIndex in my model items since they will need to know there position independently of any model queries since they are passed around to other widgets and will update independently and I cannot guarantee QItemSelectionModel::Current will be the currently editing (widget edits data, it does not edit from the view) item.

After researching QTreeWidgetItem I cannot determine how it knows it's position in a view other then it must be internally keeping a QPersistentModelIndex.

My questions are:
1. Will keeping a QPersistentModelIndex with each item create significant amount of overhead? (Model size can possibly be very large)?
2. Is this how QTreeWidgetItem does this? Or is there a better way I am missing? (I will never be able to guarantee that the current selection is the item that is changing)

Thanks,
Bob

caduel
11th December 2008, 10:53
QModelIndex::isValid() does not guarantee that the index is still valid (it was valid, when it was created).

An index may become invalid whenever the model is changed (an obvious example being "you have an index to the last row, and that row is removed").

You must ensure that a QModelIndex you have obtained is not used anymore after a random modification to the model.

Each QPersistentModelIndex adds overhead to the model: all these are checked/adjusted when the model is changed (in a relevant way).

HTH

coderbob
16th December 2008, 11:32
QModelIndex::isValid() does not guarantee that the index is still valid (it was valid, when it was created).

That does not seem to make sense the way I interpreted the docs. If it was valid when it was created and isValid() does not guarantee it is still valid then what is the point of the function?

The way I understand it isValid() is called before you use the index to ensure it is still valid before you attempt to access it. Otherwise it seems it is only there to ensure you did indeed get a valid index when it was created. The existence of this call would mean there would have to be the possibility that the a newly created index may not always be valid.

Unless I am reading what you typed wrong it appears that you are saying it is always valid when it is created and isValid() does not guarantee validity. Seems to me you can't have it both ways, and it negates the existence of the isValid call.

I did solve my problem by keeping a pointer to the model in each item (not the greatest way to do things and makes c++ encapsulation purist angry) and I call QAbstractItemModel->updateModelLayout() whenever the appropriate data has changed that requires a view upate.

This gets rid of the overhead from QPersistentModelIndex tracking gives a universal way to update any data changes in the item (since the model is already set to handle them) and appears in testing to only be a small overhead in cycles.

Thank you for the help on the issue.

Bob

caduel
16th December 2008, 14:34
The way I understand it isValid() is called before you use the index to ensure it is still valid before you attempt to access it. Otherwise it seems it is only there to ensure you did indeed get a valid index when it was created. The existence of this call would mean there would have to be the possibility that the a newly created index may not always be valid.

What I meant to say is: isValid() guarantees that the index "is valid", in the sense that it pointed to some cell in the model (not the root cell).
However, the index might have become "invalid" (in the same sense like a C++ STL iterator, or a pointer) by some modifications to the model. The QModelIndex does not know about such modifications.

Short: QModelIndex::isValid() is talking about "does this index point to some cell or to 'root'".
The other validity is talking about "is that pointer still valid?", in the sense "may I still use the pointer?". The QModelIndex does not contain any information about the second kind of validity (just like a raw pointer does not know whether it is pointing at a valid memory address).

So, you have to ensure that between the moment a QModelIndex is generated, passed around and finally used, the model is *not* modified. Otherwise the index might be invalid (without knowing it).
QPersistentModelIndexes (like QPointers) know about having become invalid due to model changes. (If not that would be a bug in the model.)

HTH