根据 C++ 的语义,您关于“删除”索引的问题没有任何意义。您根本无法销毁从函数内部按值返回的对象 - 至少在不诉诸有目的的肮脏黑客的情况下是这样。所以让我们忘记它吧。
The dataChanged
信号和索引的生命周期并没有真正相关。当你的index()
方法返回一个索引,你不是可以“删除”它的人;无论谁给你的模特打电话index()
方法负责破坏索引。没关系,您给出的索引无论如何都不会分配在空闲存储中,因此删除的概念根本不适用。
The QModelIndex
盒子上写着:索引。当谈到如何使用它时,它非常像 C++ 迭代器。它带有一些与迭代器警告相同的警告:
它必须由模型使用工厂方法创建index()
。在内部你使用createIndex()
工厂在模型中为您创建它。想想 C++ 容器的迭代器返回方法(begin()
, end()
, etc.).
必须立即使用,然后丢弃。如果您对模型进行更改,它将不再有效。同样的一般限制也适用于 C++ 容器迭代器。
如果您需要随着时间的推移保留模型索引,请使用QPersistentModelIndex
。 C++ 标准库不提供此功能。
索引的生命周期是您无法控制的。你创建它,你把它分发出去,并期望它会根据这个协议被使用。用户(例如视图)在使用它时应遵守上面列出的限制。例如,如果一个视图保留索引的时间太长(通过干预修改),那么它会导致未定义的行为(例如崩溃),这是完全可以接受的。
当您发出(或接收,如果您是视图或代理模型)时dataChanged
,您不应期望在此之前给出的任何索引仍然可用。当然,持久索引应该仍然有效,但是如果删除了指向的索引(想象一下从电子表格中删除了一个单元格,not单元格的数据被更改!)。
如果您给出了索引,则发出dataChanged
, and any当你的模型的方法被旧的索引调用时,你可以自由地崩溃、断言、中止等等。
我们还要明确一下您如何使用dataChanged
:只要给定索引处的数据项发生变化,您就应该发出它。您应该尽可能具体:它是not如果事实上一切都没有改变,那么简单地告诉你的观点一切都改变了,这是一个好主意。如果一个索引发生了变化,则发出信号topLeft
and bottomRight
设置为相同的索引。如果一个小矩形区域发生了变化,则发出该矩形的角点。如果多个不相关的项目发生了更改,并且距离太远而无法有意义地捆绑在一个小的封闭索引矩形中,则应该为每个更改的项目单独指示此类更改。
你绝对应该使用模型测试验证您的模型行为是否正常。
这可以通过添加modeltest.cpp
and modeltest.h
到您的项目,并为每个模型实例实例化测试器。您可以直接在模型中执行此操作:
#include "modeltest.h"
MyModel(QObject * parent) : ... {
new ModelTest(this, parent);
...
}
您还需要处理模型的持久索引,这是一个单独的问题。文档说:
为可调整大小的数据结构提供接口的模型可以提供 insertRows()、removeRows()、insertColumns() 和 removeColumns() 的实现。实现这些功能时,重要的是在模型尺寸发生变化之前和之后通知任何连接的视图:
- insertRows() 实现必须在将新行插入数据结构之前调用 beginInsertRows(),并在之后立即调用 endInsertRows()。
- insertColumns() 实现必须在将新列插入数据结构之前调用 beginInsertColumns(),并在之后立即调用 endInsertColumns()。
- 从数据结构中删除行之前,removeRows() 实现必须调用 beginRemoveRows(),并在之后立即调用 endRemoveRows()。
- 从数据结构中删除列之前,removeColumns() 实现必须调用 beginRemoveColumns(),并在之后立即调用 endRemoveColumns()。
这些函数发出的私有信号使附加组件有机会在任何数据变得不可用之前采取行动。使用这些开始和结束函数封装插入和删除操作还使模型能够正确管理持久模型索引。如果您希望正确处理选择,则必须确保调用这些函数。如果插入或删除带有子项的项目,则无需为子项调用这些函数。换句话说,父项将照顾其子项。