Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct
[SOLVED] QAbstractItemModel::dataChanged() question
I'm new to Qt and I'm trying to implement my own QAIM to use it in a QTreeView using Qt 5.2 (QT Creator on Win 7 x64).
My data model is tree-like with just two levels under the invisible root node, let's call them "Runs" and "Laps" (1 run can contain 1 or more laps).
Laps can be double-clicked to get "selected" and I keep track of who is selected and who's not (with a QList in the QAIM containing pointers to lap items that are selected). One of the column in the QTreeView shows the selection index of the item (i.e. the position of the item pointer in the QList of selected items).
My problem is this: it is my understanding that as double clicking changes the data, I have to call dataChanged() to notify the associated view(s). The problem is that even if I do it, the QTreeView does not get updated.
if instead of calling dataChanged() on the item I have changed (something like dataChanged(lap, lap)) I call it with two invalid indexes (i.e. dataChanged(QModelIndex(), QModelIndex())) then the view is updated. Probably an un-safe hack.
if I don't call dataChanged (or if I call it on the single item I've modified), the relevant line in the view is not updated, but gets updated when I mouse-over it (actually when I de-mouse-over, as when I double click I'm on the item). Not quite what I want and could be an implementation detail that could disappear (read it here: "http://stackoverflow.com/questions/16561974/when-to-emit-datachanged-from-a-qabstractitemmodel":http://stackoverflow.com/questions/16561974/when-to-emit-datachanged-from-a-qabstractitemmodel).
The best I can do right now is to call dataChanged(first, last) with first and last being my first and last 1st level items, so that the entire data structure is considered changed.
Trying to understand why the dataChanged(lap, lap) has no effect, I'm wondering if this comes from the fact that I'm emitting this signal from within a slot triggered by the "doubleClicked" signal in my QTreeView ...
Any idea ?
I've put my code here (there's a .pro for QT Creator): "https://drive.google.com/uc?export=download&id=0BzmU7Qoo77i1aHc2b05NZ1dvRVk":https://drive.google.com/uc?export=download&id=0BzmU7Qoo77i1aHc2b05NZ1dvRVk
Search for "PROBLEM" in runmodel.cpp to get to the relevant lines.
I'm not sure if I understand fully but I'll try.
First thing - did you notice that clicking on the Runs/Laps column would give a different index than clicking on the Sel column? (since every QModelIndex is row+column+parent)
I assume you have the "no effect" when you double click on the Runs/Laps column but if you would double click the Sel column you would immediately see the 1.
But there's still a problem.
I double clicked the sel column for the first, second and third laps (1, 2, 3) and now I'm deselecting the 1. And you issue a signal telling the view that the data changed at the index of (1) - why would the rest of the tree be updated? You just said that this one specific index of data was modified and that is indeed what I see (I need to hover over (2) to make it become (1)).
So your dataChanged signal works, but you are not using the correct indexes that changed.
With the way your ordering works it seems that indeed the change could potentially always affect the whole tree.
Thanks frankiefrank for the reply.
You're right, I was missing the fact the index "points" to the column I double click on. Thanks !
I was already aware of the second problem you highlighted (the fact one double-click can change "rows" other than the one I've double-clicked on), this is still work in progress.
One thing I don't understand though is why when I use dataChanged(index(0, 0), index(0, rowCount())) , marking as changed all my 1st level rows but only on column 0 (Runs/Laps), the whole view gets refreshed, including child nodes and columns other than column 0.
This is something I may want to do (as updating only the specific node that have changed may be too complex and the performance hit of updating all will be no issue), but I don't get why it behaves like that.
dataChanged arguments are topLeft and bottomRight, and each index is made of row+column.
So when you say
@dataChanged(index(0, 0), index(0, rowCount()))@
That's a bit weird, because A. You're passing rowCount() in a column-related parameter, and B. either way you look at it, the row/columns start at 0 so you'd never have a row/column which is count() and not count()-1.
Just think about the code that needs to handle that signal. It would go row after row, column after column. i.e. If you wanted to say the 2 whole first rows got changed you'd need to send out something like that:
@dataChanged(index(0, 0), index(1, columnCount() - 1))@
Wait, reading your comment again, maybe it's just that you wanted to try something like this?
dataChanged(index(0, 0), index(rowCount() - 1, 0))@
[quote author="frankiefrank" date="1395651650"]Wait, reading your comment again, maybe it's just that you wanted to try something like this?
dataChanged(index(0, 0), index(rowCount() - 1, 0))@[/quote]
Yep, indeed ! I must have been very drunk.
All solved now: I update manually (and properly) the items that may have changed and all works fine.
Thanks a lot for your help !
I should start drinking too! :)
Please change your post's title to include [SOLVED] in the beginning.