При попытке создания древовидной иерархической модели на базе QAbstractItemModel для QTreeView, и создания кнопки "переместить элемент вниз", столкнулся с неприятным багом в moveRows (точнее - beginMoveRows).
Я получил ошибку:
ASSERT: "!this->isEmpty()" in file ..\..\include/QtCore/../../src/corelib/tools/qstack.h
Но ведь никакого QStack явно не используется!
При попытке выяснить причину, оказалось, что программа падает на вызове endMoveRows, если sourceRow < destinationChild. (Реализация "переместить вверх" была тривиальна, но "вниз"... )
Нашлись следующие чем-то похожие баги:
https://bugreports.qt.io/browse/QTBUG-6940
https://bugreports.qt.io/browse/QTBUG-24337
Решение:
Если sourceRow < destinationChild уже нельзя использовать beginMoveRows, и поэтому решением было использовать сигналы layoutAboutToBeChanged и layoutChanged. (Я генерировал их, передавая индексы, однако без параметров тоже всё работает отлично.)
Так же добавил проверку beginMoveRows на истинность для других ситуаций.
Code fragment:
bool TreeModel::moveRows (const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) {
...
if(sourceRow > destinationChild) {
// See https://bugreports.qt.io/browse/QTBUG-6940
if(!beginMoveRows(sourceParent, sourceRow, sourceRow+count-1, destinationParent, destinationChild))
return false;
// Действия с данными здесь
endMoveRows();
return true;
}
// Because Qt bug :(. with endMoveRows, indexes and qstack.
if(sourceRow < destinationChild) {
QList<QPersistentModelIndex> parents;
parents << QPersistentModelIndex(sourceParent) << QPersistentModelIndex(destinationParent);
emit layoutAboutToBeChanged(parents);
// Действия с данными здесь
emit layoutChanged(parents);
return true;
}
...
}
Я получил ошибку:
ASSERT: "!this->isEmpty()" in file ..\..\include/QtCore/../../src/corelib/tools/qstack.h
Но ведь никакого QStack явно не используется!
При попытке выяснить причину, оказалось, что программа падает на вызове endMoveRows, если sourceRow < destinationChild. (Реализация "переместить вверх" была тривиальна, но "вниз"... )
Нашлись следующие чем-то похожие баги:
https://bugreports.qt.io/browse/QTBUG-6940
https://bugreports.qt.io/browse/QTBUG-24337
Решение:
Если sourceRow < destinationChild уже нельзя использовать beginMoveRows, и поэтому решением было использовать сигналы layoutAboutToBeChanged и layoutChanged. (Я генерировал их, передавая индексы, однако без параметров тоже всё работает отлично.)
Так же добавил проверку beginMoveRows на истинность для других ситуаций.
Code fragment:
bool TreeModel::moveRows (const QModelIndex &sourceParent, int sourceRow, int count, const QModelIndex &destinationParent, int destinationChild) {
...
if(sourceRow > destinationChild) {
// See https://bugreports.qt.io/browse/QTBUG-6940
if(!beginMoveRows(sourceParent, sourceRow, sourceRow+count-1, destinationParent, destinationChild))
return false;
// Действия с данными здесь
endMoveRows();
return true;
}
// Because Qt bug :(. with endMoveRows, indexes and qstack.
if(sourceRow < destinationChild) {
QList<QPersistentModelIndex> parents;
parents << QPersistentModelIndex(sourceParent) << QPersistentModelIndex(destinationParent);
emit layoutAboutToBeChanged(parents);
// Действия с данными здесь
emit layoutChanged(parents);
return true;
}
...
}