1

How can you implement the data function of QAbstractListModel such that it returns something with properties that are visible from a QML ListView's delegate?

For the item type, I tried implementing a QObject subclass that has Q_PROPERTYs, but QAbstractListModel::data returns QVariant, and a QObject* can't be converted to QVariant?

How do I create a QVariant that has named properties visible to QML?

class MyListItem : public QObject { Q_OBJECT Q_PROPERTY(type name READ name WRITE set_name NOTIFY nameChanged) /*...*/ public: MyListItem(QObject* parent, const QString& name) : QObject(parent) { set_name(name); } }; class MyList : public QAbstractListModel { public: MyList(QObject* parent); Q_INVOKABLE int rowCount(const QModelIndex &parent = QModelIndex()) const override; Q_INVOKABLE QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override; QVector<MyListItem*> items; }; Q_INVOKABLE int MyList::rowCount(const QModelIndex &) const { return items.size(); } Q_INVOKABLE QVariant MyList::data(const QModelIndex &index, int) const { MyListItem* item = items[index.row()]; return item; // <--- ERROR } 

Getting:

In member function ‘virtual QVariant MyList::data(const QModelIndex&, int) const’: error: use of deleted function ‘QVariant::QVariant(void*)’ 18 | return item; | ^~~~ 
2
  • please provide a minimal reproducible example, and a QVariant if it can contain a pointer to QObject so I think the problem is another Commented Dec 23, 2020 at 4:01
  • @eyllanesc: See update. Can't convert QObject* to QVariant Commented Dec 23, 2020 at 4:24

1 Answer 1

4

If you want to encapsulate a QObject in a QVariant then you must use QVariant::fromValue:

return QVariant::fromValue(item); 

MWE:

main.cpp

#include <QAbstractListModel> #include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQmlContext> class MyListItem : public QObject { Q_OBJECT Q_PROPERTY(QString name READ name WRITE set_name NOTIFY nameChanged) public: MyListItem(const QString& name, QObject* parent=nullptr) : QObject(parent), m_name(name) { } QString name() const{ return m_name; } public slots: void set_name(QString name){ if (m_name == name) return; m_name = name; emit nameChanged(m_name); } signals: void nameChanged(QString name); private: QString m_name; }; class MyList : public QAbstractListModel { public: enum MyListRoles { ItemRole = Qt::UserRole + 1 }; MyList(QObject* parent=nullptr): QAbstractListModel(parent){} ~MyList(){ qDeleteAll(items); items.clear(); } void append(MyListItem *item){ beginInsertRows(QModelIndex(), rowCount(), rowCount()); items.append(item); endInsertRows(); } int rowCount(const QModelIndex &parent=QModelIndex()) const override{ if(parent.isValid()) return 0; return items.count(); } QVariant data(const QModelIndex &index, int role) const override{ if(!index.isValid()) return {}; if(index.row() <0 || index.row() >= rowCount()) return {}; if(role == ItemRole) return QVariant::fromValue(items[index.row()]); return {}; } QHash<int, QByteArray> roleNames() const override{ return {{ItemRole, "item"}}; } private: QVector<MyListItem*> items; }; #include "main.moc" int main(int argc, char *argv[]) { #if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); #endif QGuiApplication app(argc, argv); MyList model; model.append(new MyListItem("foo1")); model.append(new MyListItem("foo2")); model.append(new MyListItem("foo3")); QQmlApplicationEngine engine; engine.rootContext()->setContextProperty("mylist", &model); const QUrl url(QStringLiteral("qrc:/main.qml")); QObject::connect(&engine, &QQmlApplicationEngine::objectCreated, &app, [url](QObject *obj, const QUrl &objUrl) { if (!obj && url == objUrl) QCoreApplication::exit(-1); }, Qt::QueuedConnection); engine.load(url); return app.exec(); } 

main.qml

import QtQuick 2.12 import QtQuick.Window 2.12 Window { width: 640 height: 480 visible: true title: qsTr("Hello World") ListView{ anchors.fill: parent model: mylist delegate: Text { text: model.item.name } } } 

enter image description here

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, this was very helpful. Also, a part I was missing was the notion of roles. After implementing roleNames and observing the role parameter of QAbstractListModel::data I've now got it working. (I thought that the references in the ListView delegate were properties of a QObject - this is not so - they are using the roles mechanism)

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.