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
Code:
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
Code:
/* Author: Remy van Elst, https://raymii.org
* License: GNU AGPLv3
*/
#include "ThingieListModel.h"
#include <QDebug>
ThingieListModel
::ThingieListModel(QObject *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;
}
{
if (!index.isValid())
{
}
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:
}
}
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();
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();
}
{
qDebug() << "print";
for(int i = 0; i < _thingies.size(); ++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#Lxhaaq...glXgZWYC6yyrv4
Based on the article: https://raymii.org/s/tutorials/Qml_D...Cpp_Model.html
Re: QML Drag and Drop including reordering the C++ model
This sounds to me like an "off by one" error. If you are keeping the same iterator or row numbers without taking into account that you have added, removed, or rearranged rows, then your iterator or index becomes invalid once you have altered the first position.
Sorry, I don't have time today to look at your complete code. I've been burned by this same kind of problem, so it seems a logical place for you to start looking.