QTreeView + sort model + QStandardItemModel, the most efficient way to update the model?
-
Hey guys,
I wrote a little application demonstrating the usage of
QAbstractTableModel
with generic table-like data. It can be found here and can easily handle 500.000+ items. As long as there's enough memory, there's no real maximum border.Unless building a customized sort system,
QAbstractItemModel::sort()
changes the original item order - which usually comes with a lot of problems. Thus, I decided to use also aQSortFilterProxyModel
approach. This can be improved as well, but is fast enough for the demo.It is noteworthy, that item creation is about at least twice as fast, as with the tweaked
QStandardItemModel
approach. Memory footprint should also be much smaller.@Violet-Giraffe Hope this helps to improve your understanding of Qt-MV programming.
-
Thanks a lot, this looks interesting! Definitely a very, very useful example.
I expect a whole bunch of problems from switching tree view to table view and fromQAbstractItemModel
toQAbstractTableModel
, but I'll give it a try! -
I've just tried
QTableView
and immediately recalled why I didn't use it in the first place. It just looks bad:http://i.imgur.com/DQusulq.png
Two problems with it:
- The top and bottom margins of every item are too huge, at least 5 times bigger than in a
QTreeView
; - despite the selection mode being set to "Select rows", the current item cursor (dotted frame) is only drawn around a specific column, not the whole row. This also isn't a problem with
QTreeView
. Here's a tree view screen shot for comparison: http://i.imgur.com/ICp2gNA.png
And I'd say the general visual style of the tree view (selection etc.) is better and looks more native to Windows. But the table does indeed work a bit faster.
- The top and bottom margins of every item are too huge, at least 5 times bigger than in a
-
To 1: Take a look here or better try the following:
tableView->verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); tableView->setStyleSheet( QStringLiteral("QAbstractItemView::item{ margin: 0; padding: 0; }") );
To 2: What's wrong with that? Same applies to QTreeView. This depends on the selection model used. You can simply set behaviour:
tableView->selectionModel().setSelectionBehaviour( QAbstractItemView::SelectRows );
Btw.: I don't want to confuse you, but do you know there's a
QDirModel
prepared for you? This seems pretty much like what you're looking for. Found a nice tutorial. -
Very interesting, I'll try your suggestions, shortly, thanks.
On 2: I have set selection behavior to "Select rows" for the view, but not the model. It worked for tree view, but not for table view, so it confused me.I have heard of the
QDirModel
. I'm making a file manager, so I need a flexible and powerful solution. Which means I have to write it all myself. Besides, I need to separate the model (UI level code) from the actual data (core level). -
Wait,
QItemSelectionModel
doesn't have asetSelectionBehaviour
member! So I can't dotableView->selectionModel().setSelectionBehaviour( QAbstractItemView::SelectRows );
-
Another observation: doing
verticalHeader()->setSectionResizeMode(QHeaderView::ResizeToContents); setStyleSheet("QAbstractItemView::item{ margin: 0; padding: 0; }");
Totally kills performance. Looks like the view does a LOT of relayouting, or maybe just calculating font metrics for each item. Something like that, judging from the call stack. Either way, the UI thread is 100% busy and the event loop is barely executing.
-
Wait, QItemSelectionModel doesn't have a setSelectionBehaviour member! So I can't do
Right, but QAbstractItemView has:
tableView->setSelectionBehaviour( QAbstractItemView::SelectRows );
-
@Violet-Giraffe Just try without setting resize mode.
Further, the css rule might not be right. Sorry, you need to figure that out by yourself.
-
@antis said:
Right, but QAbstractItemView has:
tableView->setSelectionBehaviour( QAbstractItemView::SelectRows );
That it does! And like I said, I have set this option. the table view does select a whole row, but it does not span the cursor across the whole row. While the tree view does both no problem.
-
That it does! And like I said, I have set this option. the table view does select a whole row, but it does not span the cursor across the whole row. While the tree view does both no problem.
Got me. The dotted rectangle's shows the editing focus. Logically, the focus lies always on the focused table cell. In a QTreeView on the other hand, it lies on the the tree item. You can paint the focus rect over the whole table row by overriding "QTableView::paint".
-
First, the table view is what you want for your use case. So please don't switch the view.
Ok, I did some further research:
My default file manager (and the file dialogs itself) display the focus around the item in the first column. This makes total sense, as this is the only editable column (the file name). The flag is defined inQAbstractTableModel::flags
, which you need to override:Qt::ItemFlags MyTableModel::flags(const QModelIndex & index) const { if (index.column() > 0) { // remove focusable flag for all columns > 0 return QAbstractTableModel::flags(index) & ~Qt::ItemIsEditable; } return QAbstractTableModel::flags(index); }
EDIT: Corrected the code snippet.
-
Thanks. This is counter-intuitive, but as long as I can fix it reliably for all platforms with 3 lines of code - why not. I've already reverted the change from
QtreeView
toQTableView
under the pressure of the issues, but it won't take too long to try again.Filling
QTableView
is about twice as fast asQtreeView
, so that's a good incentive, but theQtreeView
definitely looks better on Windows (more native). At least so far. For example, the selection style is much different.