Using C++ model in QML
-
I have a ListView in my QML file with a model from C++. The model have a QString, a bool and a QList.
The model works perfect when I don't use the QList:
QList<QObject*> dataList; DataObject *ob = new DataObject("main", false); dataList.append(ob); dataList.append(new DataObject("Item 2", false)); dataList.append(new DataObject("Item 3", true)); dataList.append(new DataObject("Item 4", true)); QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
But the DataObject class contains a QList that contains a list of DataObject classes. Here is where I have problems, as I can't make my project compile.
I have tried declaring my instance variable as a list of QVariant pointers:
private: QString m_group; bool m_checked; QList<QVariant*> m_elements;
But my addElement method will not compile, complaining about:
no matching member function for call to 'append'void DataObject::addElement(DataObject *ob) { m_elements.append(QVariant::fromValue(ob)); }
What am I doing wrong here?
-
@imyrvold
So hwo aboutQList<DataObject*> dataList
? and then the rest as usual i.e appendingDataObject
directly instead ofQVariant
-
@p3c0
The first thing I tried, was as you suggested, but this doesn't quite work, because I want dataList to function as a ListView model, like this:Item { width: 200 height: childView.contentHeight visible: mainRow.expanded ListView { id: childView anchors.fill: parent model: elements delegate: groupsDelegate focus: true } }
DataObject *ob = new DataObject("main", false); DataObject *ob1 = new DataObject("hr", true); DataObject *ob2 = new DataObject("ht", true); ob->addElement(ob1); ob->addElement(ob2); dataList.append(ob); dataList.append(new DataObject("Item 2", false)); dataList.append(new DataObject("Item 3", true)); dataList.append(new DataObject("Item 4", true)); QQmlContext *ctxt = engine.rootContext(); ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList));
My addElement is:
void DataObject::addElement(DataObject *ob) { m_elements.append(ob); }
I get the two elements in the ListView, but QML doesn't recognize them to be a ListModel, because I get a reference error in the log and they shows up without the group name
qrc:/TreeView.qml:40: ReferenceError: elements is not defined
qrc:/TreeView.qml:61: ReferenceError: group is not defined
qrc:/TreeView.qml:73: ReferenceError: elements is not defined
qrc:/TreeView.qml:40: ReferenceError: elements is not defined
qrc:/TreeView.qml:61: ReferenceError: group is not defined
qrc:/TreeView.qml:73: ReferenceError: elements is not defined
qml: [object Object]
qml: [DataObject(0x7faceb2958b0),DataObject(0x7faceb295970)]and the two console.log lines shows the difference between the checkModel and the elements list (the last with the list of DataObject's).
The result is this:
-
Here is an example of how I want the ListModel to be:
ListModel { id:listModel ListElement { group: "main" elements: [ ListElement { group: "hr" elements: [ ListElement { group: "mainarmA" elements: [] }, ListElement { group: "mainarmC" elements: [] }, ListElement { group: "mainarmE" elements: [] } ] }, ListElement { group: "ht" elements: [ ListElement { group: "mainarmD" elements: [] } ] } ] } ListElement { group: "aux" elements: [ ListElement { group: "hr" elements: [ ListElement { group: "mainarmB" elements: [] } ] } ] } }
Then it should look like this:
-
-
@p3c0
I didn't know that. I will investigate it, certainly. Thank you for the tip! -
To wrap this up, I have concluded that setting the QQmlContext property doesn't work in my case. I found another way to do it, that works perfectly, with the same DataObject, and that is to use QMetaObject to invokeMethod in my ListModel with the DataObject as parameter, and append the DataObject in the invoked function.
In the following main.cpp listing which shows this, the commented out lines are the ones that for some reason didn't work:#include <QApplication> #include <QQmlApplicationEngine> #include <QQmlComponent> //#include <QQmlContext> #include <qqml.h> #include <QQuickItem> #include <QQuickView> #include "dataobject.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); QQmlApplicationEngine engine; // QList<QObject*> dataList; DataObject *ob = new DataObject("main", false); DataObject *ob1 = new DataObject("hr", false); DataObject *ob2 = new DataObject("ht", true); DataObject *ob11 = new DataObject("mainarmA", false); DataObject *ob12 = new DataObject("mainarmC", false); DataObject *ob13 = new DataObject("mainarmE", true); DataObject *ob21 = new DataObject("mainarmD", true); ob1->addElement(ob11); ob1->addElement(ob12); ob1->addElement(ob13); ob2->addElement(ob21); ob->addElement(ob1); ob->addElement(ob2); QVariant v; v = QVariant::fromValue(ob); // dataList.append(ob); // QQmlContext *ctxt = engine.rootContext(); // ctxt->setContextProperty("checkModel", QVariant::fromValue(dataList)); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); QMetaObject::invokeMethod((QObject *)engine.rootObjects().first()->findChild<QObject *>("checklistModel"), "appendElement", Q_ARG(QVariant, v)); return app.exec(); }
and the ListModel with the invoked function:
ListModel { id:checklistModel objectName: "checklistModel" function appendElement(ob) { checklistModel.append(ob) } }
-
@imyrvold Glad that you found the solution :) But to be future ready use
TreeView
as the view andQAbstractItemModel
as the model.