QML Drag and Drop including reordering the C++ model
-
Hello everyone!
Please help me figure out how to deal with drag and drop in QML with reordering data in the model.
I have a model in C++. Drag and drop delegates are implemented in QML. When moving a delegate, the change must be saved in the model. At the same time, it should be possible to create copies of delegates immediately after the element from which the copy is created. Copying also works. However, there is a catch...For example, I have a list displayed:
1
2
3
I drag the 3rd element to the place of the second, I get
1
3
2
after which I want to create a copy of the first element and in QML I see this
1
3
1
2
that is, the copy is inserted not after the copied element, but after the element that I dragged.
In C++, the order of elements in QList is correct, but it does not correspond to what QML displays
If you do not drag anything, then everything works correctly
In this case, if you do beginResetModel and endResetModel in
void ThingieListModel::move(int from, int to)
, then everything works correctly. But in my case, this solution does not work, since in the current project, delegates are loaded asynchronously using Loader and when beginResetModel is called, the UI displays how they are all reloaded/* Author: Remy van Elst, https://raymii.org * License: GNU AGPLv3 */ #include "ThingieListModel.h" #include <QDebug> ThingieListModel::ThingieListModel(QObject *parent) : QAbstractListModel(parent) { } void ThingieListModel::updateFromVector(std::vector<Thingie*> newThingies) { qDebug() << "updateFromVector"; beginResetModel(); _thingies.clear(); for (const auto &item : newThingies) { _thingies << item; } endResetModel(); } QHash<int, QByteArray> ThingieListModel::roleNames() const { QHash<int, QByteArray> roles; roles[NameRole] = "name"; roles[ColorRole] = "color"; roles[ModelIndexRole] = "modelIndex"; return roles; } QVariant ThingieListModel::data(const QModelIndex &index, int role) const { if (!index.isValid()) { return QVariant(); } const Thingie *thingie = _thingies[index.row()]; switch (role) { case NameRole: return thingie->name(); case ColorRole: return thingie->color(); case ModelIndexRole: if (std::find(_thingies.begin(), _thingies.end(), thingie) != _thingies.end()) { int d = std::distance(_thingies.begin(), std::find(_thingies.begin(), _thingies.end(), thingie)); qDebug() << d; return d; } else { return -1; } default: return QVariant(); } } int ThingieListModel::rowCount(const QModelIndex &) const { return _thingies.count(); } void ThingieListModel::move(int from, int to) { qDebug() << "move " << from << ";" << to; if(from >= 0 && from < rowCount() && to >= 0 && to < rowCount() && from != to) { if(from == to - 1) { // Allow item moving to the bottom to = from++; } // beginResetModel(); beginMoveRows(QModelIndex(), from, from, QModelIndex(), to); qInfo() << "model move from: " << from << " to: " << to; _thingies.move(from, to); endMoveRows(); // endResetModel(); } } void ThingieListModel::createDublicate(int index) { int insertPosition = index + 1; beginInsertRows(QModelIndex(), insertPosition, insertPosition); Thingie *newThingie = new Thingie{_thingies[index]->name(), static_cast<int>(_thingies.size()), this}; newThingie->setColor(_thingies[index]->color()); _thingies.insert(insertPosition, newThingie); endInsertRows(); } QString ThingieListModel::print() { qDebug() << "print"; QString tmp; for(int i = 0; i < _thingies.size(); ++i) { tmp.append(QString::number(i)); tmp.append(": "); tmp.append(_thingies.at(i)->name()); tmp.append("; "); } return tmp; }
-
Here is a link to the full code: https://mega.nz/file/XQlQECqa#LxhaaqWAmvVyTEFLd3MtnMCnRcmU9glXgZWYC6yyrv4
Based on the article: https://raymii.org/s/tutorials/Qml_Drag_and_Drop_example_including_reordering_the_Cpp_Model.html