Pulling QList from C++ to qml



  • Hello,

    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?



  • Hi,

    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.

    Regarding the QVariantList issue: this is interesting, as I thought QVariantList was automatically converted to JavaScript array. If the variant containing the QObject* isn't being transformed into a JavaScript object wrapping a QObject*, then either something is going wrong (eg, unregistered type, bug, etc) or something else is going on. Are you able to call a C++ function from within the "refreshData" function, where that C++ function takes a QVariant arg and returns a QObject* value (and uses QVariant::fromValue<QObject*>(variant) to get it from the arg)?

    Cheers,
    Chris.



  • 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)
                             );
    

    @
    @
    function refreshData(arrData)
    {
    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.

    http://doc.qt.nokia.com/4.7-snapshot/qdeclarativeengine.html#qmlRegisterType



  • 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*>)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.