Pulling QList from C++ to qml
Last year I've used a QList<QObject*> inside QML by passing the list to through a QVariant to QML the following way:
QMetaObject::invokeMethod(rootObject(), "refreshData", Q_ARG(QVariant, QVariant::fromValue(qListOfQObjectPtr));
I have this working in a project without Q_DECLARE_METATYPE(MyClassInheritsQObject*) macro where it simply compiles.
In all other projects I have to use the macro or QVariant complains it doesn't know the type.
I was wondering how it is possible that last year's project just works (and compiles up to today) without the metatype macro.
I'm using QObject* and I can call Q_INVOKABLE functions with it inside QML but there is no Q_DECLARE_METATYPE macro anywhere in the project (even searched with Notepad++ through all project files).
How is it possible that QML knows my QObject subclass?
Btw: I'm also not having any custom QML items using registerType, it's just a plain Object subclass with some data and Q_INVOCABLE functions.
Another issue I'm having is that it seems impossible to read from a QVariantList which contains QObject*:
QMetaObject::invokeMethod(rootObject(), "refreshData", Q_ARG(QVariant, myVariantList));
The QML function refreshData(arr) can access arr but nothing can be done with the variant (which contains a QObject*).
How can I call for example a Q_INVOCABLE function from the variant?
Function invocation on a QObject* in QML is pretty special - the function signature is matched as closely as possible by introspecting the methods reported by the object's metaobject, and then the matching method is invoked. Q_INVOKABLE like Q_SLOT etc makes the function available through the metaobject by registering it with the metaobject system.
Note that QList<QObject*> has definitely been declared as a metaobject by QML internally (since we use QList<QObject*> in various places, eg the implementation of the QtQuick Item's "children" property requires (IIRC) QList<QObject*> to be registered as a metatype already.
So, in short: QML doesn't know your QObject subclass. But, so long as you make your derived class' methods and properties available through the metaobject system (via Q_PROPERTY, Q_INVOKABLE, Q_SLOTS, Q_ENUM etc), QML is able to introspect instance objects' metaobjects and access those methods and properties.
Thank you for your reply.
So if do not need the Q_DECLARE_METATYPE macro if I return my pointer as QObject* but I do need the macro if I want to return MyClass* regardless whether my called functions are Q_INVOKABLE (or registrated through some other way) or not.
With what I learned from this I was able to work around the QVariantList problem by simply sending the variant as a QObject* instead of MyClass*
myVariantList.append(QVariant::fromValue((QObject*)new DataContainer("data from myVariantList"))); QMetaObject::invokeMethod(rootObject() , "refreshData" , Q_ARG(QVariant, myVariantList) );
myText.text = "";
for (var i = 0; i < arrData.length; ++i)
myText.text += arrData[i].getData() + "\n";
}//everything works :)
I believe that if I want to be able to use the DataContainer class I need the Q_DECLARE_METATYPE macro to tell QVariant what it is but also a registration of the type with qmlRegisterType so that it actually works inside QML.
I will try this out later but I do not understand why everything just works with QObject* and why it doesn't with MyClass* since MyClass IS a QObject after all.
I figured that I was missing an include somewhere so that in one project I had to do nothing while in the other my code just worked. After a search it appears that including qdeclarativecontext.h does the job.
So I need to put this macro in the .cpp file or include the qdeclarativecontext.h header.
C:\Qt\4.8.0\src\declarative\qml\qdeclarativecontext.h (1 hits)
Line 110: Q_DECLARE_METATYPE(QList<QObject*>)