View Full Version : Performance with QTreeView and QAbstractItemModel

22nd November 2011, 02:11
I've seem some other posts describing problems with performance with QAbstractItemModel, but nothing that quite matches my issue. I was using a table model, but have decided that I need some rows to expand to display supplemental information for the row, and the tree model/view seems to be ideal for that. The tricky thing is that one column of data may need to flash every half-second.

When I was using the table model, I implemented a slot, connected it to a timer, scan through the data rows to determine which ones need to flash, and then emit dataChanged for the cell where flashing is needed. I also flip a bool value in there. In the "data" method, I check the flag and switch the drawing colors for the foreground and background roles. This works fine with good performance, even with my data model of 2000 rows and every item in that one column flashing for all rows. CPU is at about 8%, and flashing clearly occurs on time.

When I switched to QAbstractItemModel and QTreeView, I had to implement "index" and "parent" as well, plus make a few other minor adjustments, and the performance is abysmal. CPU is at 100%, and it's only able to flash about every three seconds. Since I haven't added any of the supplmental data, the model is essentially identical, so I was a bit shocked at the perfomance difference.

The flashing is clearly the issue because if I disable it, everything is good. One improvement I've already tried is to emit dataChanged fewer times; for simplicity, I originally emitted it once for each cell (so it was emitted 2000 times every half-second), but when I hit this problem, I changed it to emit for contiguous cells. (All cells in the column currently flash, so now it's emited once every half-second.) That didn't make any difference at all, at least not noticeably (and suprisingly).

I couldn't think of any way to implement flashing other than emitting dataChanged for the cells that need to redraw every half-second. I'm a little frustrated with the fact that the model is responsible for visualization items (fonts, colors, and so on), rather than the view. In this case, I have to emit dataChanged for many, many rows that aren't on view.

I've considered pretending that the flashable column is doubled, and alternating between which one is shown in the model. It's a weird idea, and I haven't yet tried it because it seems like it might introduce more problems than it solves, but I'm at a bit of a loss here.

I see that there's a dataChanged slot in the view, and if I knew which rows were visible in the view, I could call that slot, but the view doesn't seem to provide me with an easy way to get the top-left and bottom-right model indexes of what's currently visible.



Added after 19 minutes:

I found that "setUniformRowHeights (true)" on the QTreeView solved the performance problem, and since my row heights are indeed uniform, that's a workable solution. Apparently, recalculating independent sizes for each changed cell was the issue.

However, I'm still interested in hearing about better ways to implement flashing in a tree or table view. I suspect delegates might be involved, but I haven't figured them out yet. The whole model/view documentation, including the two books I have, is pretty inadequate, at least the instant you jump off into the slightest of unusual territories. There's just not enough detail.


23rd November 2011, 00:18
The whole model/view documentation, including the two books I have, is pretty inadequate

The book "Advanced Qt Programming" by Mark Summerfield has extensive treatment of the M/V architecture, especially tree-based models. As with any book, it probably won't cover exactly what you are doing, but there is more than enough to understand what to do.

As for the flashing, it seems to me that a QStyledItemDelegate would be the way to go on this, possibly along with a UserRole or something similar in your model. The model simply needs to set a flag that indicates flashing / non-flashing; the item delegate then sets up a timer to redraw the item at the appropriate interval. The *only* time you need to issue a data change signal is when the flag is toggled, *not* every 500 msec. There's no need to get the model involved in actually controlling the flashing itself; it simply need to tell views when the item's flash flag has been flipped.

23rd November 2011, 01:30
Thanks for the help. I'll looked into the QStyledItemDelegate in more detail. I have the book you mentioned, and I've found the M/V chapter(s) to be less helpful than I would like, but I'll try wading through it again.