Removing multiple rows from TableView
-
wrote on 17 Aug 2016, 13:00 last edited by
Hi,
I am trying to remove multiple rows from a TableView. I have a selection and on deletion action traverse the selected rows with
tableView.selection.forEach(function(rowIndex) {myModel.deleteRow(rowIndex)})
Now what happens is that the first selected row is deleted and the view is updated. Then the next row is deleted but since one line has already been deleted, all the row indexes below are now shifted by 1.
How is the approach here in general?
- Find a way to not update the view between the deletions?
- Recalculate the index after every deletion?
Thanks for any hints.
-
Hi,
There are usually three ways:
- Do it in reverse order
- Keep deleting the starting row for the number of rows to remove.
- If your model is base on QAbstractItemModel, call removeRows on it with the start index and the count
Hope it helps
-
wrote on 18 Aug 2016, 07:59 last edited by
Thank you for your answer.
I forgot to mention that the selection is not contiguous.
So I guess it's 1. then. I will try that out later today. -
wrote on 18 Aug 2016, 13:05 last edited by
OK, so far so bad. :)
Since I am using a QSortFilterProxyModel, I cannot make any assumptions about the "real"rowIndex
position. So I cannot tell which row is the "last" one that should be removed first.I have now added a unique ID to my data source and will try to identify the rows to remove that way. Will post my solution soon'ish. :)
-
wrote on 18 Aug 2016, 18:13 last edited by
function removeSelectedRows() { for (var i = selection.__ranges.length - 1 ; i >= 0 ; -- i) { var index = selection.__ranges[i][0]; var count = 1 + selection.__ranges[i][1] - selection.__ranges[i][0]; model.remove(index, count) } selection.clear() }
This worked for me, but I'm not using a QSortFilterProxyModel.
-
function removeSelectedRows() { for (var i = selection.__ranges.length - 1 ; i >= 0 ; -- i) { var index = selection.__ranges[i][0]; var count = 1 + selection.__ranges[i][1] - selection.__ranges[i][0]; model.remove(index, count) } selection.clear() }
This worked for me, but I'm not using a QSortFilterProxyModel.
wrote on 22 Aug 2016, 08:35 last edited byHi,
looks tempting (though not with QSqortFilterProxyModel) but for my understanding breaks with two "best practices" of the QML world.
- limit the use of JavaScript to UI logic and put your business logic into the C++ backend
- avoid double-underscore
__methods
because they are private and can change with any minor version of Qt
My approach will be to fill an array with all the selected rows on the QML side, hand that to my
ProxyModel
(C++), remap therowIndexes
there to the ones of mySqlTableModel
, hand that new list to that model and then try to remove all rows in one transaction withQSqlQuery::execBatch
. Not sure if I succeed (still a beginner) but this feels like a good approach.Regards
-
wrote on 22 Aug 2016, 11:37 last edited by
So here is what works for me.
Please comment if you think there are things to improve. :)
What I do is:- View: create a list of selected rows and give that list to the ProxyModel
- ProxyModel: map the proxy row indexes to the table row indexes and give the new list to the SqlTableModel
- SqlTableModel: remove the rows in reverse order to not shift the remaining row indexes in the list
The QML...
Menu { id: contextMenu MenuItem { text: qsTr("Delete") shortcut: "Del" onTriggered: { var selectedRows = [] tableView.selection.forEach(function(rowIndex) {selectedRows.push(rowIndex)}) myModel.deleteRows(selectedRows) tableView.selection.clear() tableView.selection.select(tableView.currentRow) } } }
...the ProxyModel...
void ProxyModel::deleteRows(QVariantList selectedRows) { QVector<int> rowsToDelete; for (QVariant row : selectedRows) { QModelIndex proxyIdx = index(row.toInt(), 0); QModelIndex sourceIdx = mapToSource(proxyIdx); rowsToDelete.append(sourceIdx.row()); } qobject_cast<SqlTableModel*>(sourceModel())->deleteRows(rowsToDelete); }
...and the ugly ... err, the SqlTableModel
void SqlTableModel::deleteRows(QVector<int> rows) { bool success; for (auto it = rows.crbegin(); it != rows.crend(); ++it) { int row = *it; beginRemoveRows(QModelIndex(), row, row); success = removeRow(row); if (success == true) { endRemoveRows(); } } }
1/7