Qt QAbstractItemModel - 项目删除崩溃 [英] Qt QAbstractItemModel - item removal crashes
问题描述
我在使用Qt类编写一个应用程序,我有一个层次结构,我需要在树视图中显示它(我使用的QTreeView小部件)。数据本身如下所示:
I'm writing an application using Qt classes where I have a hierarchical structure and I need to display it in a tree view (I'm using a QTreeView widget). The data itself look like this:
class StatisticsEntry
{
// additional data management methods
...
bool setData(int column, const QVariant &value)
{
if (column < 0 || column >= _data.size())
return false;
_data[column] = value;
return true;
}
private:
// each item has a parent item except the top-most one
StatisticsEntry *_parent;
// each item may have child items which are accessible through the following member
QList<StatisticsEntry*> _children;
// each item is defined by a set of vallues stored in the following vector
QVector<QVariant> _data;
}
我有一个叫StatModel的类实现QAbstractItemModel-使用它来操纵和呈现存储在StatisticsEntry树中的数据。
类有一个名为addStatisticsData的方法,我用它将StatisticsEntry记录推入模型。方法大致如下:
I have a class called it StatisticsModel that implements QAbstractItemModel - use it to manipulate and present the data stored in the StatisticsEntry tree. The class has a method called addStatisticsData which I use to push StatisticsEntry records into the model. The method roughly looks like this:
QModelIndex StatisticsModel::addStatisticsData(const QString &title, const QString &description, const QModelIndex &parent)
{
int row = rowCount(parent);
if (!insertRow(row, parent))
return QModelIndex();
// Get new item index
QModelIndex child = index(row, 0, parent);
// set item data
setTitle(child, title);
setDescription(child, description);
return child;
}
SetTitle和setDescription方法是相同的 - 这里是setTitle:
SetTitle and setDescription methods are identical - here's the setTitle one:
void StatisticsModel::setTitle(const QModelIndex &index, const QString& title)
{
QModelIndex columnIndex = this->index(index.row(), StatColumn::Title, index.parent());
this->setData(columnIndex, title, Qt::EditRole);
}
setData方法如下:
The setData method is as follows:
bool StatisticsModel::setData(const QModelIndex &index, const QVariant &value, int role)
{
if (role != Qt::EditRole)
return false;
int column = index.column();
StatisticsEntry *item = getItem(index);
if (!item->setData(column, value))
return false;
emit dataChanged(index, index);
return true;
}
剩下的是getItem方法:
What is left is the getItem method:
StatisticsEntry *StatisticsModel::getItem(const QModelIndex &index) const
{
if (index.isValid())
{
StatisticsEntry *item = static_cast<StatisticsEntry*>(index.internalPointer());
if (item)
return item;
}
return _rootItem;
}
这是关于添加新的和修改现有条目。在我的应用程序中,我已经实现了QSortFilterProxyModel,没有什么特别的,只是lessThan方法。我使用代理模型在QTreeView中提供一个显示数据的排序功能。有以下代码将模型连接到树视图窗口小部件:
That is about all there is when speaking of adding new and modifying existing entries. In my application I have implemented QSortFilterProxyModel as well - nothing special, just the lessThan method. I use the proxy model to provide a sort feature in the QTreeView that displays the data. There is the following code that connects the models to the treeview widget:
在主窗口的标题:
...
StatisticsModel* _statisticsModel;
StatisticsProxyModel* _statisticsProxyModel;
...
在主窗口的构造函数中
...
_statisticsModel = new StatisticsModel(ths);
_statisticsProxyModel = new StatisticsProxyModel(htis);
...
_statisticsProxyModel->setSourceModel(_statisticsModel);
ui->statisticsTreeView->setModel(_statisticsProxyModel);
...
应用程序还有一个按钮,从模型 - 我目前只测试与QTreeView :: selectionModel() - > currentIndex,暂时没有多重选择。
The application also has a button that allows me to remove the selected item from the model - I'm currently only testing with the QTreeView::selectionModel()->currentIndex, no multi-selections for the time being.
我有以下代码的StatisticsModel :: removeRows方法
I have the following code for the StatisticsModel::removeRows method
bool StatisticsModel::removeRows(int position, int rows, const QModelIndex &parent)
{
StatisticsEntry *parentItem = getItem(parent);
bool success1 = true;
bool success2 = true;
beginRemoveRows(parent, position, position + rows - 1);
for (int i = position + rows - 1; i >= position; i--)
{
QModelIndex child = index(i, 0, parent);
QString title = this->title(child); // the title method is the getter method that matches the setTitle one
success1 = success1 && removeRows(0, rowCount(child), child); //rowCount is implemented to return the number of items stored in StatisticsEntry::_children list for the specified parent index
success2 = success2 && parentItem->removeChild(i); // deletes an entry from the StatisticsEntry::_children list
}
endRemoveRows();
return success1 && success2;
}
$ b <我得到一个异常,堆栈跟踪看起来像:
The problem is that sometimes when I remove an item using QAbstractItemModel::removeRow method I get an exception and the stack trace looks like:
StatisticsModel::parent StatisticsModel.cpp 307 0x13e7bf8
QModelIndex::parent qabstractitemmodel.h 393 0x72e57265
QSortFilterProxyModelPrivate::source_to_proxy qsortfilterproxymodel.cpp 386 0x711963e2
QSortFilterProxyModel::mapFromSource qsortfilterproxymodel.cpp 2514 0x7119d28b
QSortFilterProxyModel::parent qsortfilterproxymodel.cpp 1660 0x7119a32c
QModelIndex::parent qabstractitemmodel.h 393 0x72e57265
QPersistentModelIndex::parent qabstractitemmodel.cpp 347 0x72e58b86
QItemSelectionRange::isValid qitemselectionmodel.h 132 0x70e3f62b
QItemSelection::merge qitemselectionmodel.cpp 466 0x711503d1
QItemSelectionModelPrivate::finalize qitemselectionmodel_p.h 92 0x7115809a
QItemSelectionModelPrivate::_q_rowsAboutToBeRemoved qitemselectionmodel.cpp 623 0x71151132
QItemSelectionModel::qt_static_metacall moc_qitemselectionmodel.cpp 113 0x711561c2
QMetaObject::activate qobject.cpp 3547 0x72e8d9a4
QAbstractItemModel::rowsAboutToBeRemoved moc_qabstractitemmodel.cpp 204 0x72f08a76
QAbstractItemModel::beginRemoveRows qabstractitemmodel.cpp 2471 0x72e5c53f
QSortFilterProxyModelPrivate::remove_proxy_interval qsortfilterproxymodel.cpp 558 0x71196ce7
QSortFilterProxyModelPrivate::remove_source_items qsortfilterproxymodel.cpp 540 0x71196c7f
QSortFilterProxyModelPrivate::source_items_about_to_be_removed qsortfilterproxymodel.cpp 841 0x71197c77
QSortFilterProxyModelPrivate::_q_sourceRowsAboutToBeRemoved qsortfilterproxymodel.cpp 1291 0x711995cc
QSortFilterProxyModel::qt_static_metacall moc_qsortfilterproxymodel.cpp 115 0x7119d506
QMetaCallEvent::placeMetaCall qobject.cpp 525 0x72e883fd
QObject::event qobject.cpp 1195 0x72e894ba
QApplicationPrivate::notify_helper qapplication.cpp 4550 0x709d710e
QApplication::notify qapplication.cpp 3932 0x709d4d87
QCoreApplication::notifyInternal qcoreapplication.cpp 876 0x72e6b091
奇怪的是,这似乎与本项目有关的所有拆除立即方法调用发生后,已经结束了。看起来代理模型正在寻找不应该出现的模型索引(或者我认为)。 StatisticsModel :: parent方法如下:
Oddly enough this seems to happen after all immediate method calls concerning the item removal are already over. It seems that the proxy model is looking for model indices that should not be present anymore (or so I think). The StatisticsModel::parent method is as follows:
QModelIndex StatisticsModel::parent(const QModelIndex &index) const
{
if (!index.isValid())
return QModelIndex();
StatisticsEntry *childItem = getItem(index);
StatisticsEntry *parentItem = childItem->parent();
if (NULL != parentItem)
return createIndex(parentItem->childNumber(), 0, parentItem);
return QModelIndex();
}
当发生异常时,与childItem和parentItem变量方法似乎无效 - 指针本身指向不可访问的内存,或者成员QLists没有条目或者它们的条目给出内存访问冲突。
这可能是父类的方法不正确,但随后如何获取父指数 - 该文件化QAbstractItemModel阻碍QModelIndex在该方法的使用::母公司为它会创建一个无限递归
When the exception happens the values associated with the childItem and parentItem variables from the above method seem invalid - either the pointers themselves point to non-accessible memory or the member QLists either have no entries or their entries give Memory access violation. It may be that the parent method is not correct, but then how to fetch the parent index - the qabstractItemModel documentation discourages the usage of QModelIndex::parent in that method for it will create an infinite recursion.
任何帮助都会感激,
推荐答案
> StatisticsModel :: removeRows ,你是嵌套 begingRemoveRows / endRemoveRows
,其中,AFAIK,不工作。你应该这样做:
When doing your StatisticsModel::removeRows
, You are nesting begingRemoveRows/endRemoveRows
, which, AFAIK, does not work. You should do:
bool StatisticsModel::removeRows(int position, int rows, const QModelIndex &parent)
{
StatisticsEntry *parentItem = getItem(parent);
bool success1 = true;
bool success2 = true;
for (int i = position + rows - 1; i >= position; i--)
{
QModelIndex child = index(i, 0, parent);
QString title = this->title(child); // the title method is the getter method that matches the setTitle one
success1 = success1 && removeRows(0, rowCount(child), child); //rowCount is implemented to return the number of items stored in StatisticsEntry::_children list for the specified parent index
beginRemoveRows(parent, i, i);
success2 = success2 && parentItem->removeChild(i); // deletes an entry from the StatisticsEntry::_children list
endRemoveRows();
}
return success1 && success2;
}
这篇关于Qt QAbstractItemModel - 项目删除崩溃的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!