How to properly link C++ model to QML front end when Interfacing with a server
-
here is my setup:
First is the model class, this stores a pointer to the data of type
CompetitionsList
. We can see that it implements the necessary basic functions when deriving fromQAbstractListModel
, and it uses theQML_ELEMENT
macro to expose the model to the QML type system:class CompetitionsListModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(CompetitionsList* list READ list WRITE setList) QML_ELEMENT public: explicit CompetitionsListModel(QObject *parent = nullptr); enum { NameRole = Qt::ItemDataRole(), IdRole }; int rowCount(const QModelIndex &parent = QModelIndex()) const override; QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; CompetitionsList *list() const; void setList(CompetitionsList *list); virtual QHash<int, QByteArray> roleNames() const; private: CompetitionsList* m_list; \\ <--- ptr to data };
Then we have the data class. This class is also a
QML_ELEMENT
, and it has auserid
property. This is used to populate theQVector<listItem>
by requesting data from a RESTful http server.The two signals
preItemAppended()
andpostItemAppended()
are emitted when data is added to theQVector<listItem>
. These signals are then connected to the Model as a way of notifying the model it must create a new row in the list. The important function here ispopulateCompetitions
, which I explain below.struct listItem { QString competitionName; QString competitionId; }; class CompetitionsList : public QObject { Q_OBJECT Q_PROPERTY(QString userId READ getUserId WRITE setUserId) QML_ELEMENT public: explicit CompetitionsList(QObject *parent = nullptr); void populateCompetitions(const QString& userId); QVector<listItem> items(); QString getUserId() const; void setUserId(const QString &value); signals: void preItemAppended(); void postItemAppended(); void errorPopulatingData(); private: QVector<listItem> m_competitions; QString userId; };
The
populateCompetitions
function looks as so:void CompetitionsList::populateCompetitions(const QString &userId) { qDebug() << "initialising data"; HttpClient* client = new HttpClient(); client->getUserCompetitions(userId); connect(client, &HttpClient::getUserCompetitionsResult, [=](const QByteArray& reply){ QJsonDocument _reply = QJsonDocument::fromJson(reply); if(_reply["data"].isNull()) { emit errorPopulatingData(); } else { const QJsonArray competitions = _reply["data"]["competitions"].toArray(); for(const QJsonValue& competition : competitions) { emit preItemAppended(); listItem item{competition["competition-name"].toString(), competition["competition-id"].toString()}; m_competitions.append(std::move(item)); emit postItemAppended(); } } }); }
It requests data from the database, and then stores it locally.
Then finally, the QML model which ties it all together:
ListView { id: view implicitHeight: 1920 implicitWidth: 1080 clip: true model: CompetitionsListModel { list: CompetitionsList { id: compList } Component.onCompleted: { compList.userId = "6033f377257e8630ed13299e" } //<-- calls the populateCompetitions function } delegate: RowLayout { Text { text: qsTr(model.name + ":::" + model.id) } } }
We can see that it has a
ListView
element, with a model of typeCompetitionsListModel
and a list of typeCompetitionsList
. Once the model component is created, we set the userId of the list, this in turn calls thepopulateCompetitions
function which sets up the data for the model to use as seen above.Unfortunately this doesnt anything when I run the code. Blank screen. Nada. I was wondering if anyone has an insight as to what might be causing this based on the code provided. Ive been at it for so long and it just inst being nice.
Thanks for any help given. Sorry about all the code - its hard to reproduce in a minimal way.