QTreeView/QAbstractItemModel - 删除导致异常
QTreeView/QAbstractItemModel - delete causes exception
我写了一个从 QAbstractModelItem 派生的 class。它用于 QTreeView。遗憾的是,官方文档示例没有显示如何在模型上添加或删除项目。我认为这很容易做到,所以我破解了它。问题是删除所选对象会导致异常。示例:
用户单击 QTreeView 上的一行并希望删除它及其所有子项(如果有)。这是被执行的代码:
MyModel.cpp:
// This gets called with the QModelIndex of the currently selected row.
void MyModel::remove(const QModelIndex &index) {
if (!index.isValid())
return;
MyItem * selectedItem = static_cast<MyItem*>(index.internalPointer());
beginRemoveRows(index, index.row(), index.row());
// Call the method on the selected row object that will delete itself and all its children:
selectedItem->destroy();
endRemoveRows();
}
MyItem.h:
// A pointer list with child items.
std::vector<MyItem*> children;
MyItem.cpp:
// Deletes all children of this object and itself.
void MyItem::destroy(bool isFirst) {
if (children.size() > 0) {
// Each child needs to run this function, to ensure that all nested objects are properly deleted:
for each (auto child in children)
child->destroy(false);
// Now that the children have been deleted from heap memory clear the child pointer list:
children.clear();
}
// This boolean determines wether this object is the selected row/highest object in the row hierachy. Remove this object from the parent's pointer list:
if(isFirst)
parent->removeChild(this);
// And lastly delete this instance:
if(!isFirst) // This will cause a memory leak, but it is necessary
delete this; // <- because this throws an exception if I run this on the first object.
}
// Removes a single child reference from this instance's pointer list.
void MyItem::removeChild(MyItem * child)
{
auto it = std::find(children.begin(), children.end(), child);
children.erase(it);
}
现在,如果我们不介意轻微的内存泄漏,这就可以正常工作了。 ^^
但是,如果我尝试 运行 first/selected 行对象上的删除命令 - 则会发生以下两个异常之一:
- 该行有子行:
抛出异常:读取访问冲突。这是 0xDDDDDDDD。
- 该行没有子行:
抛出异常:写入访问冲突。 _Parent_proxy 是 0x64F30630。
我保持代码简短但希望它包含我的错误。或者有人知道一个很好的 QTreeView/QAbstractItemModel 示例来说明如何 add/remove 项目吗?
亲切的问候
索拉
我认为 MyModel::remove
方法有错误。 beginRemoveRows
将父索引作为第一个参数,而不是索引本身。你必须用这个替换行:
beginRemoveRows(index.parent(), index.row(), index.row());
我写了一个从 QAbstractModelItem 派生的 class。它用于 QTreeView。遗憾的是,官方文档示例没有显示如何在模型上添加或删除项目。我认为这很容易做到,所以我破解了它。问题是删除所选对象会导致异常。示例:
用户单击 QTreeView 上的一行并希望删除它及其所有子项(如果有)。这是被执行的代码:
MyModel.cpp:
// This gets called with the QModelIndex of the currently selected row.
void MyModel::remove(const QModelIndex &index) {
if (!index.isValid())
return;
MyItem * selectedItem = static_cast<MyItem*>(index.internalPointer());
beginRemoveRows(index, index.row(), index.row());
// Call the method on the selected row object that will delete itself and all its children:
selectedItem->destroy();
endRemoveRows();
}
MyItem.h:
// A pointer list with child items.
std::vector<MyItem*> children;
MyItem.cpp:
// Deletes all children of this object and itself.
void MyItem::destroy(bool isFirst) {
if (children.size() > 0) {
// Each child needs to run this function, to ensure that all nested objects are properly deleted:
for each (auto child in children)
child->destroy(false);
// Now that the children have been deleted from heap memory clear the child pointer list:
children.clear();
}
// This boolean determines wether this object is the selected row/highest object in the row hierachy. Remove this object from the parent's pointer list:
if(isFirst)
parent->removeChild(this);
// And lastly delete this instance:
if(!isFirst) // This will cause a memory leak, but it is necessary
delete this; // <- because this throws an exception if I run this on the first object.
}
// Removes a single child reference from this instance's pointer list.
void MyItem::removeChild(MyItem * child)
{
auto it = std::find(children.begin(), children.end(), child);
children.erase(it);
}
现在,如果我们不介意轻微的内存泄漏,这就可以正常工作了。 ^^
但是,如果我尝试 运行 first/selected 行对象上的删除命令 - 则会发生以下两个异常之一:
- 该行有子行: 抛出异常:读取访问冲突。这是 0xDDDDDDDD。
- 该行没有子行: 抛出异常:写入访问冲突。 _Parent_proxy 是 0x64F30630。
我保持代码简短但希望它包含我的错误。或者有人知道一个很好的 QTreeView/QAbstractItemModel 示例来说明如何 add/remove 项目吗?
亲切的问候 索拉
我认为 MyModel::remove
方法有错误。 beginRemoveRows
将父索引作为第一个参数,而不是索引本身。你必须用这个替换行:
beginRemoveRows(index.parent(), index.row(), index.row());