ListView delegate isnt able to access model properties after inserting into QAbstractItemModel
-
I have a QAbstractItemModel that I am exposing to Qml to display. When inserting a new item into it, I properly call the
beginInsertRows(QModelIndex(), index, index);
andendInsertRows();
functions. The item gets inserted correctly, but my delegate (in a ListView):delegate: Rectangle { width: bookmarksView.width height: 24 color: "red" opacity: 0.5 Label { id: bookmarkName anchors.centerIn: parent text: model.name color: Style.colorText font.pointSize: 11 } }
gives me an error that it cant assign unkown to QString on the line
text: model.name
, but after reloading the page it works fine. So it just isnt able to access it right after I have inserted the new item.Does someone have an idea why this happens?
-
The problem was a missing reference on the container. It should have been
QList<Bookmark>&
, thus it didnt update the container when I add a book. -
@Creaperdown Might be better if this is posted to https://forum.qt.io/category/12/qml-and-qt-quick category.
-
@Creaperdown said in ListView delegate isnt able to access model properties after inserting into QAbstractItemModel:
it here since the issue might be on the c++ side of QAbstractItemModel
If so why don't you show us your model implementation?
-
@Christian-Ehrlicher good point, here it is:
class ADAPTERS_EXPORT BookmarksModel : public QAbstractListModel { Q_OBJECT public: enum Roles { UuidRole = Qt::UserRole, NameRole, PageNumberRole, YOffsetRole }; BookmarksModel(const QList<domain::entities::Bookmark>& data); int rowCount(const QModelIndex& parent) const override; QVariant data(const QModelIndex& index, int role) const override; QHash<int, QByteArray> roleNames() const override; public slots: void startInsertingBookmark(int index); void endInsertingBookmark(); void startDeletingBookmark(int index); void endDeletingBookmark(); void bookmarkNameChanged(int row); private: const QList<domain::entities::Bookmark> m_data; };
cpp:
BookmarksModel::BookmarksModel(const QList<domain::entities::Bookmark>& data) : m_data(data) { } int BookmarksModel::rowCount(const QModelIndex& parent) const { if(parent.isValid()) return 0; return m_data.size(); } QVariant BookmarksModel::data(const QModelIndex& index, int role) const { if(!index.isValid()) return QVariant(); const Bookmark& bookmark = m_data.at(index.row()); switch(role) { case UuidRole: return bookmark.getUuid(); case NameRole: return bookmark.getName(); case PageNumberRole: return bookmark.getPageNumber(); case YOffsetRole: return bookmark.getYOffset(); default: return QVariant(); } } QHash<int, QByteArray> BookmarksModel::roleNames() const { static QHash<int, QByteArray> roles { { UuidRole, "uuid" }, { NameRole, "name" }, { PageNumberRole, "pageNumber" }, { YOffsetRole, "yOffset" }, }; return roles; } void BookmarksModel::startInsertingBookmark(int index) { beginInsertRows(QModelIndex(), index, index); } void BookmarksModel::endInsertingBookmark() { endInsertRows(); } void BookmarksModel::startDeletingBookmark(int index) { beginRemoveRows(QModelIndex(), index, index); } void BookmarksModel::endDeletingBookmark() { endRemoveRows(); } void BookmarksModel::bookmarkNameChanged(int row) { emit dataChanged(index(row, 0), index(row, 0), { NameRole }); }
The bookmarks are added from another class, that is emitting signals that are connected to the public slots like
startInsertingRow
, ... I have checked the connections and they are triggered correctly. -
This is how a bookmark is added:
auto book = getBook(); emit bookmarkInsertionStarted(book->getBookmarks().count()); book->addBookmark(bookmark); emit bookmarkInsertionEnded();
and here you can see that these signals are connected to the slots:
connect(m_bookService, &application::IBookService::bookmarkInsertionStarted, m_bookmarksModel.get(), &data_models::BookmarksModel::startInsertingBookmark); connect(m_bookService, &application::IBookService::bookmarkInsertionEnded, m_bookmarksModel.get(), &data_models::BookmarksModel::endInsertingBookmark);
-
I am exposing a SortFilterProxyModel with my BookmarksModel set as the source, but I do not think that this should cause any problems.
-
@Creaperdown said in ListView delegate isnt able to access model properties after inserting into QAbstractItemModel:
void BookmarksModel::startInsertingBookmark(int index)
{
beginInsertRows(QModelIndex(), index, index);
}void BookmarksModel::endInsertingBookmark()
{
endInsertRows();
}void BookmarksModel::startDeletingBookmark(int index)
{
beginRemoveRows(QModelIndex(), index, index);
}void BookmarksModel::endDeletingBookmark()
{
endRemoveRows();
}Imo this should not be exposed to the outside. Write a custom function in your model which adds/removes a bookmark and call begin/endFoo() in there. Otherwise the user of your model must know that he needs to call startInsertingBookmark() / endInsertBookmark() for every inserted bookmark. Also I don't see a function which really adds something to the model.
-
S SGaist referenced this topic on
-
@Christian-Ehrlicher I have written a second reply, containing the function that adds the bookmark.
Does moving the functions into the model make a difference functionality wise? Using the signal-approach should be doing exactly the same, shouldn't it?
I am using this approach throughout my application to separate the code responsible for the qml representation from the actual logic.I'll consider moving it into the models, but for now I'd prefer to solve it this way, if it isn't the root of the problem.
-
@Creaperdown said in ListView delegate isnt able to access model properties after inserting into QAbstractItemModel:
oes moving the functions into the model make a difference functionality wise? Using the signal-approach should be doing exactly the same, shouldn't it?
Yes, but the user of your model must know to call begin/endFoo() for no reason - can be done directly in addBookmark() and nothing can go wrong then like e.g.:
emit bookmarkInsertionStarted(book->getBookmarks().count()); book->addBookmark(bookmark); book->addBookmark(bookmark); emit bookmarkInsertionEnded();
or
emit bookmarkInsertionStarted(book->getBookmarks().count()); emit bookmarkInsertionEnded();
which can be easily avoided.
But that's not the your current issue, just a bad desgin (imo).
-
@Christian-Ehrlicher thanks for the recommendation, I'll be looking into that but I'm still not sure what causes me actual issue
-
@Creaperdown There I can't help - don't use QML
-
@Christian-Ehrlicher So you think this is a qml related problem?
-
I would create a single/atomar add function to really make sure the add is correct but the rest looks good.
-
@Creaperdown
Yes indeed it is, which is why I suggested this thread might be better moved to QML forum in the first place, though never mind now. -
-
Why do you delete this thread? To start over the same discussion about the possible wrong usage of begin/endInsertRows again?
-
C Christian Ehrlicher restored this topic on
-
@Creaperdown in your model, do the following:
beginResetModel(); add new row() endResetModel();
-
@JoeCFD said in ListView delegate isnt able to access model properties after inserting into QAbstractItemModel:
@Creaperdown in your model, do the following:
beginResetModel(); add new row() endResetModel();
If you need to reset the whole model because you insert one row, there's likely a design issue.