PDA

View Full Version : How to access a QList of QObject* in QML and Qt?



TheIndependentAquarius
28th January 2015, 09:31
I need to have an array of class objects which should be accessible in Qt as well as QML.

Considering http://stackoverflow.com/a/15830797/462608 following is what I have tried.

Now I need to know how to read and write to the functions of ClassA through Qt and QML.

See the print statement in the constructor in .h file. That produces a segmentation fault.

class.h


#ifndef CLASSA
#define CLASSA

#include <QQuickItem>

class ClassA : public QObject
{
private:
Q_OBJECT

Q_PROPERTY(int one READ one WRITE setOne NOTIFY oneChanged)
int m_one;

public:
ClassA () {}
int one() const { return m_one; }

public slots:
void setOne(int arg)
{
if (m_one == arg)
return;

m_one = arg;
emit oneChanged(arg);
}

signals:
void oneChanged(int arg);
};

class ClassB : public QObject
{
private:
Q_OBJECT

Q_PROPERTY(QList <QObject*> objClassAList READ objClassAList WRITE setObjClassAList NOTIFY objClassAListChanged)
QList <QObject*> m_objClassAList;

public:
ClassB ()
{
QList <QObject*> localObjList;
for (int i = 0; i < 5; i++)
{
ClassA localObj;
localObj.setOne (100);
localObjList.push_back (&localObj);
}

setObjClassAList (localObjList);
qDebug () << "QQQQQQQQQQQQQQ: " << objClassAList ()[0]->property ("one");
}

QList <QObject*> objClassAList () const { return m_objClassAList; }

public slots:
void setObjClassAList (QList <QObject*> arg)
{
if (m_objClassAList == arg)
return;

m_objClassAList = arg;
emit objClassAListChanged(arg);
}

signals:
void objClassAListChanged (QList <QObject*> arg);
};

#endif // CLASSA


main.cpp


#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "class.h"

int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);

const char* what = "WHAT";

qmlRegisterType <ClassA> (what, 1, 0, "A");
qmlRegisterType <ClassB> (what, 1, 0, "B");

QQmlApplicationEngine engine;
engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

return app.exec();
}

main.qml


import QtQuick 2.4
import QtQuick.Window 2.2
import WHAT 1.0

Window {
visible: true

B
{
onObjClassAListChanged:
{

}
}
}

wysota
28th January 2015, 10:30
Your code makes no sense because of several things the most important being that you are storing in a list pointers to local variables that go out of scope immediately afterwards (line #48 of the first snippet).

Basically if you want a list of objects then the most straightforward solution is to use QQmlListProperty. Alternatively if your data is value based and not identity based then a simple property of type QVariantList (or even QVariant) should be enough. You can store data as QVariantMap which will be converted to a javascript object on the QML side. Since QVariantMap is itself QVariant, you can store it in QVariantList (which itself is a QVariant as well so the property can be of QVariant type). Don't follow what is written in that stack overflow thread, it's not a good solution, maybe apart the answer to use QAbstractListModel.

anda_skoa
28th January 2015, 14:15
Basically if you want a list of objects then the most straightforward solution is to use QQmlListProperty.

IMHO this is only true if the requirement is to create objects on the QML side and put them into them list.

A QList<QObject*> property is easier if the main objective is to export a list of objects from C++ to QML.

However, given the context of the stackoverflow question (list of value objects), I would also suggest the QAbstractListModel subclass approach.

Cheers,
_

wysota
28th January 2015, 14:27
IMHO this is only true if the requirement is to create objects on the QML side and put them into them list.

A QList<QObject*> property is easier if the main objective is to export a list of objects from C++ to QML.

I would agree if there was no qmlRegisterType call for A. If that was on purpose and not an act of desperation when trying to find a solution, it would imply one wants the engine to understand the difference between QObject and A - the most obvious use-case being creating such objects in QML. Accessing A's methods and properties does not require registering the class in the engine.

TheIndependentAquarius
29th January 2015, 06:53
Your code makes no sense because of several things the most important being that you are storing in a list pointers to local variables that go out of scope immediately afterwards (line #48 of the first snippet).
Thankful for pointing out the fault and the additional information you've given regarding QVariant.
Lack of concepts knowledge on my part.


Don't follow what is written in that stack overflow thread, it's not a good solution, maybe apart the answer to use QAbstractListModel.
You didn't explain why would using QObject* not be a good solution. Please explain as you would do to a layman.
Also, in which case using QObject* would be considered a good solution?


Accessing A's methods and properties does not require registering the class in the engine.
I didn't understand the context here. You mean to say that I can access a C++ class in QMl without using qmlRegisterType?

wysota
29th January 2015, 07:05
You didn't explain why would using QObject* not be a good solution. Please explain as you would do to a layman.
The thread at stackoverflow was about creating a kind of registry. It is quite limiting to only be able to read from the registry on the QML end. I don't know what your use-case is but you are trying to react on changes in the list. The list would only change if a new list was set on the property in C++. A model is a much better approach -- more consistent, less limitations albeit more difficult to implement than a simple list of objects.


Also, in which case using QObject* would be considered a good solution?
For example when you want to return a static list of objects and operate on them once in a while. That is what is bothering me in your case is that you want to react on when the list changes (of course that still could be ok depending on what you do with the data). But in general I assumed you would like to be creating instances of A (because of the register call in your code).


I didn't understand the context here. You mean to say that I can access a C++ class in QMl without using qmlRegisterType?
If it inherits QObject and you only want to access its methods and properties then you don't need qmlRegisterType. QObject is already registered. If you only need properties and if they are not being changed dynamically (I mean once set, they remain at their values) then it is simpler to use QVariant or a model.