Using pointer in C++ model for QML
-
wrote on 15 Aug 2021, 03:35 last edited by JorisC
Dear All,
I'm currently coding a c++ model for display it in a ListVieew in QML side. This point is OK for me, I have followed the c++ model in QML tutorial (https://www.youtube.com/watch?v=9BcAYDlpuT8&list=WL&index=29&t=1280s)
Problem: Contrary to the turorial, in my C++ list class I have a structure which contains a pointer ( serie_graphe* serie;) and I don't know how to access it in QML side. In QML side, I would like to deal with something like "model.serie"
serielist.h
#ifndef SERIELIST_H #define SERIELIST_H #include <QObject> #include <QVector> #include <serie_graphe.h> struct SerieItem { bool selection; serie_graphe* serie; QString nom; int id; }; class SerieList : public QObject { Q_OBJECT public: explicit SerieList(QObject *parent = nullptr); QVector<SerieItem> items() const; bool setItemAt(int index, const SerieItem &item); signals: void preItemAppended(); void postItemAppended(); public slots: void appendItem(serie_graphe* nouvelle_serie); public: QVector<SerieItem> mItems; int numero = 0; }; #endif // SERIELIST_H
serielist.cpp
#include "serielist.h" SerieList::SerieList(QObject *parent) : QObject(parent) { // mItems.append({ true, QStringLiteral("Nick ta reum")}); // mItems.append({ false, QStringLiteral("Fix the sink") }); } QVector<SerieItem> SerieList::items() const { return mItems; } bool SerieList::setItemAt(int index, const SerieItem &item) { if (index < 0 || index >= mItems.size()) return false; const SerieItem &oldItem = mItems.at(index); if (item.selection == oldItem.selection && item.nom == oldItem.nom) return false; mItems[index] = item; return true; } void SerieList::appendItem(serie_graphe* nouvelle_serie) { emit preItemAppended(); SerieItem item; item.selection = false; item.serie = nouvelle_serie; item.nom = nouvelle_serie->nom_serie; item.id = numero; mItems.append(item); numero++; //On incrémente le numéro de série en vue d'un prochain ajout emit postItemAppended(); }
Unfortunately, in the data function in seriemodel.cpp, I cannot handle "serieRole" with a Qvariant in my model (seriemodel class) ...
seriemodel.cpp
#include "seriemodel.h" #include "serielist.h" SerieModel::SerieModel(QObject *parent) :QAbstractListModel(parent) , mList(nullptr) { } int SerieModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !mList ) return 0; return mList->items().size(); } QVariant SerieModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !mList) return QVariant(); const SerieItem item = mList->items().at(index.row()); switch (role) { case SelectionRole: return QVariant(item.selection); case NomRole: return QVariant(item.nom); case SerieRole: return QVariant(item.serie); //PROBLEM HERE because item.serie is a pointer .... and cannot be handle with QVARIANT case IDRole: return QVariant(item.id); } return QVariant(); } Qt::ItemFlags SerieModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable; // FIXME: Implement me! } QHash<int, QByteArray> SerieModel::roleNames() const { QHash<int, QByteArray> names; names[SelectionRole] = "selection"; names[NomRole] = "nom"; names[SerieRole] = "serie"; names[IDRole] = "id"; return names; } SerieList *SerieModel::list() const { return mList; } void SerieModel::setList(SerieList *list) { beginResetModel(); if (mList) mList->disconnect(this); mList = list; if (mList) { connect(mList, &SerieList::preItemAppended, this, [=]() { const int index = mList->items().size(); beginInsertRows(QModelIndex(), index, index); }); connect(mList, &SerieList::postItemAppended, this, [=]() { endInsertRows(); }); } endResetModel(); }
seriemodel.h
#ifndef SERIEMODEL_H #define SERIEMODEL_H #include <QAbstractListModel> class SerieList; class SerieModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(SerieList *list READ list WRITE setList) public: explicit SerieModel(QObject *parent = nullptr); enum { SelectionRole = Qt::UserRole, NomRole, SerieRole, IDRole }; // 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; SerieList *list() const; void setList(SerieList *list); private: SerieList *mList; }; #endif // SERIEMODEL_H
In QML I would like for example:
ListView { implicitWidth: parent.width implicitHeight:parent.height anchors.fill: parent clip: true model: SerieModel { list: serieList } delegate: RowLayout { width: parent.width height: 30 CheckBox { checked: model.selection onClicked: {model.selection = checked;serieList_activePlot.appendItem(model.serie);} //HERE I would like to use model.serie } Text { text: model.nom Layout.fillWidth: true minimumPixelSize: 10 }
Thank you in advance if someone can help me to handle this pointer in order to use it in my model.serie.
Regards,
JC -
Dear All,
I'm currently coding a c++ model for display it in a ListVieew in QML side. This point is OK for me, I have followed the c++ model in QML tutorial (https://www.youtube.com/watch?v=9BcAYDlpuT8&list=WL&index=29&t=1280s)
Problem: Contrary to the turorial, in my C++ list class I have a structure which contains a pointer ( serie_graphe* serie;) and I don't know how to access it in QML side. In QML side, I would like to deal with something like "model.serie"
serielist.h
#ifndef SERIELIST_H #define SERIELIST_H #include <QObject> #include <QVector> #include <serie_graphe.h> struct SerieItem { bool selection; serie_graphe* serie; QString nom; int id; }; class SerieList : public QObject { Q_OBJECT public: explicit SerieList(QObject *parent = nullptr); QVector<SerieItem> items() const; bool setItemAt(int index, const SerieItem &item); signals: void preItemAppended(); void postItemAppended(); public slots: void appendItem(serie_graphe* nouvelle_serie); public: QVector<SerieItem> mItems; int numero = 0; }; #endif // SERIELIST_H
serielist.cpp
#include "serielist.h" SerieList::SerieList(QObject *parent) : QObject(parent) { // mItems.append({ true, QStringLiteral("Nick ta reum")}); // mItems.append({ false, QStringLiteral("Fix the sink") }); } QVector<SerieItem> SerieList::items() const { return mItems; } bool SerieList::setItemAt(int index, const SerieItem &item) { if (index < 0 || index >= mItems.size()) return false; const SerieItem &oldItem = mItems.at(index); if (item.selection == oldItem.selection && item.nom == oldItem.nom) return false; mItems[index] = item; return true; } void SerieList::appendItem(serie_graphe* nouvelle_serie) { emit preItemAppended(); SerieItem item; item.selection = false; item.serie = nouvelle_serie; item.nom = nouvelle_serie->nom_serie; item.id = numero; mItems.append(item); numero++; //On incrémente le numéro de série en vue d'un prochain ajout emit postItemAppended(); }
Unfortunately, in the data function in seriemodel.cpp, I cannot handle "serieRole" with a Qvariant in my model (seriemodel class) ...
seriemodel.cpp
#include "seriemodel.h" #include "serielist.h" SerieModel::SerieModel(QObject *parent) :QAbstractListModel(parent) , mList(nullptr) { } int SerieModel::rowCount(const QModelIndex &parent) const { if (parent.isValid() || !mList ) return 0; return mList->items().size(); } QVariant SerieModel::data(const QModelIndex &index, int role) const { if (!index.isValid() || !mList) return QVariant(); const SerieItem item = mList->items().at(index.row()); switch (role) { case SelectionRole: return QVariant(item.selection); case NomRole: return QVariant(item.nom); case SerieRole: return QVariant(item.serie); //PROBLEM HERE because item.serie is a pointer .... and cannot be handle with QVARIANT case IDRole: return QVariant(item.id); } return QVariant(); } Qt::ItemFlags SerieModel::flags(const QModelIndex &index) const { if (!index.isValid()) return Qt::NoItemFlags; return Qt::ItemIsEditable; // FIXME: Implement me! } QHash<int, QByteArray> SerieModel::roleNames() const { QHash<int, QByteArray> names; names[SelectionRole] = "selection"; names[NomRole] = "nom"; names[SerieRole] = "serie"; names[IDRole] = "id"; return names; } SerieList *SerieModel::list() const { return mList; } void SerieModel::setList(SerieList *list) { beginResetModel(); if (mList) mList->disconnect(this); mList = list; if (mList) { connect(mList, &SerieList::preItemAppended, this, [=]() { const int index = mList->items().size(); beginInsertRows(QModelIndex(), index, index); }); connect(mList, &SerieList::postItemAppended, this, [=]() { endInsertRows(); }); } endResetModel(); }
seriemodel.h
#ifndef SERIEMODEL_H #define SERIEMODEL_H #include <QAbstractListModel> class SerieList; class SerieModel : public QAbstractListModel { Q_OBJECT Q_PROPERTY(SerieList *list READ list WRITE setList) public: explicit SerieModel(QObject *parent = nullptr); enum { SelectionRole = Qt::UserRole, NomRole, SerieRole, IDRole }; // 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; SerieList *list() const; void setList(SerieList *list); private: SerieList *mList; }; #endif // SERIEMODEL_H
In QML I would like for example:
ListView { implicitWidth: parent.width implicitHeight:parent.height anchors.fill: parent clip: true model: SerieModel { list: serieList } delegate: RowLayout { width: parent.width height: 30 CheckBox { checked: model.selection onClicked: {model.selection = checked;serieList_activePlot.appendItem(model.serie);} //HERE I would like to use model.serie } Text { text: model.nom Layout.fillWidth: true minimumPixelSize: 10 }
Thank you in advance if someone can help me to handle this pointer in order to use it in my model.serie.
Regards,
JC@JorisC
the only way to make QML aware of the "serie_graphe" type is by letting "serie_graphe" derive from QObject.
Otherwise you would need to route each member/property of "serie_graphe" with adedicated item role.
Or convert your "serie_graphe" to a QVariantMap (key-value like) -
wrote on 5 Jan 2022, 09:03 last edited by
@JorisC said in Using pointer in C++ model for QML:
return QVariant(item.serie); //PROBLEM HERE because item.serie is a pointer .... and cannot be handle with QVARIANT
You can use return QVariant::fromValue(item.serie);