2

我正在试验 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 如何处理模型中的更改以及表示已插入行的正确方法是什么?

PS我不知道是否有任何源文件有用,但这是整个源代码树,这是源代码中最有趣的地方

PPS 调试后我意识到出了什么问题

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) )rootIndexQModelIndex(-1,-1,0x0,QObject(0x0) )

PPPS 在对同一应用程序的纯 C++ 版本进行了一些实验后,我发现了这个错误的原因。在上面的成员_q_rowsInserted中 parent 是我们在 class 的对象中提交beginInserRows()rootIndexQPersistentModelIndexrootIndex通常等于 QModelIndex(-1,-1,NULL,NULL)。你也应该知道 operator== of classQModelIndex比较了这个类的所有 4 个字段。

即,如果我们调用beginInsertRows(QModelIndex(),...)thanparent将是相等rootIndex的,因为这些索引都等于QMoldeIndex(-1,-1,NULL,NULL)。但是,如果我们调用,那么beginInsertRows(createIndex(-1,-1),....)我们的父级将是 aQModelIndex(-1,-1,NULL,<non-null pointer to our model>)并且它显然不会相等rootIndex ,因为 NULL != 。因此,调用 似乎是个坏主意beginInsertRows(createIndex(....),....)

有人可以解释一下 Qt 内部发生了什么吗?

(也许现在最好关闭这个问题并重新打开另一个关于 Qt 内部的更具体和具体的问题。我会考虑的。)

4

1 回答 1

0

创建 QModelIndex 的正确方法是在 row==-1 或 column==-1 时返回空 QModelIndex。重要的是不要将指向模型的指针放在结果 QModelIndex 中。如果你这样做,有些东西就不能正常工作。

于 2013-04-01T16:02:16.273 回答