我正在尝试使用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如何处理模型中的变化以及表示插入行的正确方法是什么?
P.S。我不知道是否有任何源文件有用,但这是whole source tree,这是the most interesting place in the sources
P.P.S。在debuggin之后,我意识到了什么是错的
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 ++版本的一些实验后,我发现了这个bug的原因。在上面的成员_q_rowsInserted
中,我们在beginInserRows()
中提交的值rootIndex
是类QPersistentModelIndex
的对象。 rootIndex
通常等于QModelIndex(-1,-1,NULL,NULL)。另外你应该知道class 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内部的另一个更具体和具体的问题。我会考虑它。)
答案 0 :(得分:0)
创建QModelIndex的正确方法是,如果row == - 1或column == - 1,则返回空的QModelIndex。重要的是不要在结果QModelIndex中放置指向模型的指针。如果你愿意的话,某些东西可能无法正常工作。