【发布时间】:2013-03-27 11:34:25
【问题描述】:
我正在试验 C++、QML 和 OCaml。现在我正在解决一个奇怪的问题:如果我在模型中添加新行,QML 不会自行更新。是的,我知道 beginInsetRows()...endInsertRows()。
我的模型有 1 列和 1 行。我想再添加 1 行并调用 beginInsertRows(QModelIndex(-1,-1), 1, 1),进行一些计算并调用 endInsertRows()。我添加了一些调试输出到qt5/qtbase/src/corelib/itemmodels/qabstractitemmodel.cpp
void QAbstractItemModel::endInsertRows()
{
Q_D(QAbstractItemModel);
qDebug() << "Insert QAbstractItemModel::endInsertRows()";
QAbstractItemModelPrivate::Change change = d->changes.pop();
d->rowsInserted(change.parent, change.first, change.last);
qDebug() << "emitting rowsInserted("<<change.parent<<","<<change.first<<","<<change.last<<")";
emit rowsInserted(change.parent, change.first, change.last, QPrivateSignal());
}
根据我的应用程序日志信号rowsInserted 应该被发出。
Going to call AbstractModel::beginInsertRows
Calling AbstractModel::rowCount
rowCount = 1
Going to call AbstractModel::endInsertRows
Insert QAbstractItemModel::endInsertRows()
emitting rowsInserted( QModelIndex(-1,-1,0x0,AbstractModel(0x11d3680) ) , 1 , 1 )
End inserting rows. cpp_data.length = 2
Sending event to change model
Call update (0,0)...(1,0)
Going to call AbstractModel::dataChanged
Calling AbstractModel::parent
然后我开始思考如何实现 ListView 以及它如何处理有关添加新行的信号。 grep 命令的输出真的让我大吃一惊:
......./qt5/qtdeclarative/src/quick/items$ grep rowsInserted qquicklistview*
......./qt5/qtdeclarative/src/quick/items$
那么,您能否解释一下 ListView 如何处理模型中的更改以及表示已插入行的正确方法是什么?
附:我不知道是否有任何源文件有用,但这是whole source tree,这是the most interesting place in the sources
P.P.S.调试后我意识到出了什么问题
void QQuickVisualDataModel::_q_rowsInserted(const QModelIndex &parent, int begin, int end)
{
Q_D(QQuickVisualDataModel);
if (parent == d->m_adaptorModel.rootIndex)
_q_itemsInserted(begin, end - begin + 1);
}
parent 是 QModelIndex(-1,-1,0x0,AbstractModel(0xfa9690) ) 但 rootIndex 是 QModelIndex(-1,-1,0x0,QObject(0x0) ) 并且它们不相等,这就是不引发事件的原因。需要更多时间来了解为什么会发生这种情况......
P.P.P.S.在对同一应用程序的纯 C++ 版本进行了一些实验后,我发现了这个错误的原因。在上面的成员_q_rowsInserted 中,父级是我们在beginInserRows() 中提交的值,rootIndex 是类QPersistentModelIndex 的对象。 rootIndex 通常等于 QModelIndex(-1,-1,NULL,NULL)。您还应该知道 QModelIndex 类的 operator== 比较该类的所有 4 个字段。
即如果我们调用beginInsertRows(QModelIndex(),...) 而不是parent 将等于rootIndex,因为这些索引都等于QMoldeIndex(-1,-1,NULL,NULL)。但是如果我们调用beginInsertRows(createIndex(-1,-1),....),那么我们的父级将是QModelIndex(-1,-1,NULL,<non-null pointer to our model>),它显然不等于rootIndex,因为NULL !=。所以,打电话给beginInsertRows(createIndex(....),....)似乎是个坏主意。
谁能解释一下 Qt 内部发生了什么?
(也许现在最好关闭这个问题并重新打开另一个关于 Qt 内部的更具体和具体的问题。我会考虑的。)
【问题讨论】:
-
这个问题是否与 OCaml 相关联?如果没有,请移除 ocaml 标签。
-
我认为最好按原样说,因为我不直接调用 C++ 方法,它们都被包装到 OCaml 值。
-
据我所知,没有公共 QModelIndex(int, int) 构造函数,所以我很惊讶它可以编译。你试过 QModelIndex() 吗?
-
QModelIndex() 与 QModelIndex(-1,-1) 相同