QML and C++ model not shown
-
Hello,
I'm trying to learn how to create a C++ model with QAbstractListModel to display it in a QML view but I have nothing displayed despite my attempts.
I followed the video on this Qt site: C++ Model
The only part where I don't follow the explanations is the modification of main to add my model class, because I preferred to use a BackEnd class to modify my model according to an XML file (later).
So I've got a "CustomData" class with a custom item list managed from a QAbstractListModel class whose header looks like this:
#include <QAbstractListModel> Q_MOC_INCLUDE("CustomData.h") class CustomData; class DataModel : public QAbstractListModel { Q_OBJECT public: explicit DataModel(QObject *parent = nullptr); ~DataModel(); Q_PROPERTY(CustomData *dataList READ dataList WRITE setDataList NOTIFY dataListChanged) enum { NameRole = Qt::UserRole, ValueRole = Qt::UserRole+1, TypeRole = Qt::UserRole+2 }; // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // Editable: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex &index) const override; virtual QHash<int, QByteArray> roleNames() const override; CustomData *dataList() const; void setDataList(CustomData *dataList); signals: void dataListChanged(); private: QHash<int, QByteArray> m_roleNames; CustomData *m_dataList; };
Here is the header of my BackEnd class:
/* BackEnd Class */ class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(CustomData *dataList READ dataList WRITE setDataList NOTIFY dataListChanged) QML_ELEMENT public: /* Constructor */ explicit BackEnd(QObject *parent = nullptr); /* Destructor */ ~BackEnd(); /* Public Methods */ CustomData *dataList() const; void setDataList(CustomData *newDataList); signals: void dataListChanged(); private: /* Private Methods */ /* Private Attributes */ CustomData *m_dataList; };
That's all I do in my BackEnd:
BackEnd::BackEnd(QObject *parent) : QObject{parent} { m_dataList = new CustomData(); m_dataList->appendItem(); m_dataList->appendItem(); } CustomData *BackEnd::dataList() const { return m_dataList; } void BackEnd::setDataList(CustomData *newDataModel) { m_dataList = newDataModel; emit dataListChanged(); }
My main:
qmlRegisterType<BackEnd>("BackEnd", 1, 0, "BackEnd"); qmlRegisterType<DataModel>("DataModel", 1, 0, "DataModel");
And finally, my QML view :
ListView { id: listView ... model: DataModel { id: datamodel dataList: backend.dataList }
I know that maybe I'm not showing enough code, but since there are 3 classes, I thought that the problem would already be in what I'm showing.
I think it's more how I call my model in BackEnd and my QML view because the rest is like in the video or the explanations in the Qt 6 QML book.
Thank you if you can give me your point of view.
-
@GrecKo Yes, I tried to replace my model with a ListModel and ListElement and I can see my delegates and data.
But with my custom model, it return 0 as count for now :/
Would you like more code ? I can publish my whole code here (or somewhere else more convenient ?)
-
Hello,
I'm trying to learn how to create a C++ model with QAbstractListModel to display it in a QML view but I have nothing displayed despite my attempts.
I followed the video on this Qt site: C++ Model
The only part where I don't follow the explanations is the modification of main to add my model class, because I preferred to use a BackEnd class to modify my model according to an XML file (later).
So I've got a "CustomData" class with a custom item list managed from a QAbstractListModel class whose header looks like this:
#include <QAbstractListModel> Q_MOC_INCLUDE("CustomData.h") class CustomData; class DataModel : public QAbstractListModel { Q_OBJECT public: explicit DataModel(QObject *parent = nullptr); ~DataModel(); Q_PROPERTY(CustomData *dataList READ dataList WRITE setDataList NOTIFY dataListChanged) enum { NameRole = Qt::UserRole, ValueRole = Qt::UserRole+1, TypeRole = Qt::UserRole+2 }; // Basic functionality: int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; // Editable: bool setData(const QModelIndex &index, const QVariant &value, int role = Qt::EditRole) override; Qt::ItemFlags flags(const QModelIndex &index) const override; virtual QHash<int, QByteArray> roleNames() const override; CustomData *dataList() const; void setDataList(CustomData *dataList); signals: void dataListChanged(); private: QHash<int, QByteArray> m_roleNames; CustomData *m_dataList; };
Here is the header of my BackEnd class:
/* BackEnd Class */ class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(CustomData *dataList READ dataList WRITE setDataList NOTIFY dataListChanged) QML_ELEMENT public: /* Constructor */ explicit BackEnd(QObject *parent = nullptr); /* Destructor */ ~BackEnd(); /* Public Methods */ CustomData *dataList() const; void setDataList(CustomData *newDataList); signals: void dataListChanged(); private: /* Private Methods */ /* Private Attributes */ CustomData *m_dataList; };
That's all I do in my BackEnd:
BackEnd::BackEnd(QObject *parent) : QObject{parent} { m_dataList = new CustomData(); m_dataList->appendItem(); m_dataList->appendItem(); } CustomData *BackEnd::dataList() const { return m_dataList; } void BackEnd::setDataList(CustomData *newDataModel) { m_dataList = newDataModel; emit dataListChanged(); }
My main:
qmlRegisterType<BackEnd>("BackEnd", 1, 0, "BackEnd"); qmlRegisterType<DataModel>("DataModel", 1, 0, "DataModel");
And finally, my QML view :
ListView { id: listView ... model: DataModel { id: datamodel dataList: backend.dataList }
I know that maybe I'm not showing enough code, but since there are 3 classes, I thought that the problem would already be in what I'm showing.
I think it's more how I call my model in BackEnd and my QML view because the rest is like in the video or the explanations in the Qt 6 QML book.
Thank you if you can give me your point of view.
-
@GrecKo Yes, I tried to replace my model with a ListModel and ListElement and I can see my delegates and data.
But with my custom model, it return 0 as count for now :/
Would you like more code ? I can publish my whole code here (or somewhere else more convenient ?)
-
@GrecKo Yes, I tried to replace my model with a ListModel and ListElement and I can see my delegates and data.
But with my custom model, it return 0 as count for now :/
Would you like more code ? I can publish my whole code here (or somewhere else more convenient ?)
-
Oh damn, it was that...
Example of a copy/paste tutorial without investigating the why...
My rowCount looked like this:
int DataModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid() || !m_dataList) return 0; return m_dataList->items().size(); }
This parameter and associated code is present by default, so I'm not sure what the point is and whether I should keep its implementation.
Removing the parent test in the condition fixed my problem. Thanks a lot !!!
-
-
Oh damn, it was that...
Example of a copy/paste tutorial without investigating the why...
My rowCount looked like this:
int DataModel::rowCount(const QModelIndex &parent) const { if (!parent.isValid() || !m_dataList) return 0; return m_dataList->items().size(); }
This parameter and associated code is present by default, so I'm not sure what the point is and whether I should keep its implementation.
Removing the parent test in the condition fixed my problem. Thanks a lot !!!
@Mick_1
This code'sif (!parent.isValid()) return 0;
looks like it was taken from a tree model, not a flat list like you want/have? And hence is the wrong way round for you. When you have a tree model all nodes (other than the root) have a
parent
which is valid, androwCount()
must return the count of child items. For a flat model it is always passed an invalid parent, your!parent.isValid()
will always be true and hence you will always return 0.For a flat model I would just have
Q_ASSERT(!parent.isValid()); // `parent` should never be passed in valid, else there is a logic error for a flat list if (!m_dataList) return 0; return m_dataList->items().size();
-
@Mick_1
This code'sif (!parent.isValid()) return 0;
looks like it was taken from a tree model, not a flat list like you want/have? And hence is the wrong way round for you. When you have a tree model all nodes (other than the root) have a
parent
which is valid, androwCount()
must return the count of child items. For a flat model it is always passed an invalid parent, your!parent.isValid()
will always be true and hence you will always return 0.For a flat model I would just have
Q_ASSERT(!parent.isValid()); // `parent` should never be passed in valid, else there is a logic error for a flat list if (!m_dataList) return 0; return m_dataList->items().size();
@JonB said in QML and C++ model not shown:
@Mick_1
This code'sif (!parent.isValid()) return 0;
looks like it was taken from a tree model, not a flat list like you want/have?
This is also unworkable for a tree model, if the intention is to make the top level items of the tree viewable.