I'm experimenting with C++, QML and OCaml. Now I'm fixing a strange issue: if I add new row to my model QML does not update itself. Yes, I know about beginInsetRows()...endInsertRows().
My model has 1 column and 1 row. I want to add 1 more row and I call beginInsertRows(QModelIndex(-1,-1), 1, 1)
, do some computations and call endInsertRows()
. I have added some debug output to 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());
}
According to my application log signal rowsInserted
should be emitted.
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
Than I started thinking about how is implemented ListView and how it handles signals about adding new rows. Output of grep command really suprised me:
......./qt5/qtdeclarative/src/quick/items$ grep rowsInserted qquicklistview*
......./qt5/qtdeclarative/src/quick/items$
So, Can u please explain me how ListView handles changes in the model and what is correct way to signal that rows has been inserted?
P.S. I don't know if any source files will be useful, but this is whole source tree and this is the most interesting place in the sources
P.P.S. After debuggin I realised what is wrong
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);
}
There parent
is QModelIndex(-1,-1,0x0,AbstractModel(0xfa9690) )
but rootIndex
is QModelIndex(-1,-1,0x0,QObject(0x0) )
and they are not equal and that's why event does not raised. Need more time to realise why this happens....
P.P.P.S. After some experimentations with pure-C++ version of the same application I discovered the reason of this bug. In member _q_rowsInserted
above parent is the value which we have submitted in beginInserRows()
an rootIndex
is object of class QPersistentModelIndex
. rootIndex
is usually equal QModelIndex(-1,-1,NULL,NULL). Also you should know that operator== of class QModelIndex
compares all 4 fields of this class.
I.e. if we call beginInsertRows(QModelIndex(),...)
than parent
will be equal rootIndex
because these indexes both equal to QMoldeIndex(-1,-1,NULL,NULL)
. But if we will call beginInsertRows(createIndex(-1,-1),....)
than our parent will be a QModelIndex(-1,-1,NULL,<non-null pointer to our model>)
and it will obviously not be equal rootIndex
because NULL != . So, it seems that it is a bad idea to call beginInsertRows(createIndex(....),....)
.
Can somebody explain me what happens in Qt internals?
(Maybe now is better to close this question and reopen another, more specific and concrete question about Qt internals. I'll think about it.)
Right way to create QModelIndex is to return empty QModelIndex if row==-1 or column==-1. It is important not to put pointer to model inside result QModelIndex. Something can don't work properly if u will do that.