QTreeView crashes due to deleted row
-
Dear Qt-Community
I am currently writing a CustomTreeModel, derived from a QAbstractItemModel, for a QTreeView. This model is filled with a CustomTreeItem. My tree model has methods to directly add a CustomTreeItem with data to the model and another one to remove said item, so I do not override insertRows(int row, int count, const QModelIndex &parent = QModelIndex()) and removeRows(int row, int count, const QModelIndex &parent = QModelIndex()).
My methods look like this
void CustomTreeModel::addItem(ItemData *data) { beginInsertRows( createIndex( _rootItem->row(), 0, _rootItem ), _rootItem->childCount(), _rootItem->childCount() ); _rootItem->appendChild( new CustomTreeItem( data ) ); endInsertRows(); emit layoutChanged(); }
For removing a row with a specific data set:
void CustomTreeModel::removeItem(ItemData *data) { CustomTreeItem *item = getItem( data ); beginRemoveRows( createIndex( _rootItem->row(), 0, _rootItem ), item ->row(), item ->row() ); _rootItem->removeChild( item ); delete item; endRemoveRows(); emit layoutChanged(); }
The methods work as expected. But as soon as the QTreeView updates it's content, according to the Debugger, it still has somehow a reference to the deleted item, which does not exist anymore, wants to access it and thus crashes. If I call startResetModel() / endResetModel(), at the end of my removeItem() method, the problem is solved, but unfortunately the whole QTreeView collapses all items which is then useless to the case.
Am I missing something?
Thanks for any help.
-
Why is this a QTreeModel when you only have one level? I would go with a QTableModel.
Then please remove layoutChanged() - this is not needed at all.
If it is crashing then please post a backtrace and provide a minimal, compilable example of the model. We e.g. don't know what's happening inside _rootItem->removeChild().
Also you don't check if getItem() returns a valid pointer. -
I use it for a 2 level TreeModel. The second level has another data type, so I have another set of methods like addSubItem(ItemData *data, SubItemData *subdata) and removeSubItem(ItemData *data, SubItemData *subdata). These methods query for the TreeItem which contains data and add a TreeItem child with subdata. But for testing purposes, I removed the code for the second level, thus am currently only working with the first level to solve this problem.
@Christian-Ehrlicher said in QTreeView crashes due to deleted row:
Then please remove layoutChanged() - this is not needed at all.
If I remove that, the QTreeView does not show the added item.
@Christian-Ehrlicher said in QTreeView crashes due to deleted row:
Also you don't check if getItem() returns a valid pointer.
getItem() looks like this and thus should always return a valid pointer:
CustomTreeItem *CustomTreeModel::getItem(const QModelIndex &index) const { if (index.isValid()) { CustomTreeItem *item = static_cast<CustomTreeItem*>( index.internalPointer() ); if (item) { return item; } } return _rootItem; }
@Christian-Ehrlicher said in QTreeView crashes due to deleted row:
provide a minimal, compilable example of the model. We e.g. don't know what's happening inside _rootItem->removeChild().
The implementations for the TreeItem look like this (_childItems is a QList<TreeItem*>):
void TreeItem::appendChild(TreeItem *item) { item->_parentItem = this; _childItems.append( item ); }
void TreeItem::removeChild(TreeItem *item) { _childItems.removeOne( item ); }
int TreeItem::row() const { if( _parentItem != nullptr ) { return _parentItem->_childItems.indexOf( const_cast<TreeItem*>( this ) ); } return 0; }