Issue
Implemented QML Dynamic View Ordering by Dragging View Items using this Qt tutorial: QML Dynamic View Ordering Tutorial. Original underlying model is QAbstractListModel
descendant in our case. Model stores data in a QList<QObject*> objectList;
field type. Works fine, however item ordering changed in proxy DelegateModel
only.
How to change items order automatically in original underlying model as well for other C++ and QML consumers where order matters? Or I could we otherway access some resulted (sorted) List Model model from C++ somehow?
Thanks for any help!
Solution
In the QML Dynamic View Ordering Tutorial 3 example I’ve replaced visualModel.items.move()
call with my ObjectListModel::move()
method like this:
ObjectListModel : public QAbstractListModel:
void ObjectListModel::move(int from, int to)
{
if(0 <= from && from < count() && 0 <= to && to < count() && from != to) {
if(from == to - 1) // Allow item moving to the bottom
to = from++;
beginMoveRows(QModelIndex(), from, from, QModelIndex(), to);
objectList.move(from, to);
endMoveRows();
}
}
Delegate component:
DropArea {
anchors { fill: parent; }
onEntered: {
let from = drag.source.DelegateModel.itemsIndex
let to = mouseArea.DelegateModel.itemsIndex
objectListModel.move(from, to)
}
}
And above works perfectly for the ListView
and ObjectListModel
itself – I have checked: items (and therefore objects) are moved correctly, indexes are correct, C++ consumers works just fine and take new order into account correctly, etc.
However another consumer like MapItemView
fails to use the model after beginMoveRows
/endMoveRows
calls: moved item disappeared on the map and other manipulations with an item crashes the app.
Map {
...
MapItemView {
model: objectListModel
delegate: SomeItemIndicator {
}
}
}
Reported QTBUG-81076 bug, which is confirmed.
Workaround:
Found workaround for now: created 2nd duplicate model which content will be replaced completely on every change in the 1st model on every add/delete/moving(reordering). Above works since beginResetModel
/endResetModel
works correctly for MapItemView
. So MapItemView
now utilizes only the 2nd model. So on every 1st model change this method is called for the 2nd model:
QObjectList ObjectListModel::swapObjectList(const QObjectList& newlist)
{
QObjectList oldlist(_objectList);
beginResetModel();
_objectList = newlist;
endResetModel();
return oldlist;
}
Answered By – Aleksey Kontsevich
Answer Checked By – David Goodson (BugsFixing Volunteer)