Important: Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

[SOLVED] Qt Meta-Obect System: QObject::setProperty() with QVariant user defined types - fails



  • Hello all,

    Here is my case: I have a class, MyClass, that has references to other objects (composition). I want to dynamically initialize an instance of this class using @QObject::setProperty(const char * fieldName, QVariant &value;)@
    The properties are pointers to objects that inherit QObjects. I have those pointers stored in a QObject* array (let's call it objVals) and I also have the field names in an array fieldNames.
    To do this, I create a QVariant (let's call it value) for each QObject* in the array, then call setProperty() with fieldNames[i] and value.
    For example

    @MyClass mc;
    for (int i = 0; i < numObjFields; ++i) {
    QVariant value;
    value.setValue(objVals[i]);
    mc.setProperty(fieldNames[i],value);
    }@

    if the properties' real type is not QObject*, but a derived class, setProperty fails.
    Now if I cast objVals[i] to it's true type, it succeeds (assuming I know the type at compile time of course)

    @MyClass mc;
    for (int i = 0; i < numObjFields; ++i) {
    QVariant value;
    value.setValue((trueType*)objVals[i]);
    mc.setProperty(fieldNames[i],value);
    }@

    I have declared all the types with Q_DECLARE_METATYPE, Q_OBJECT and the properties with Q_PROPERTY with the proper getters and setters.

    Why is this problem happennig? Is there a way to overcome it? Your help will be very much appreciated.

    Thanks!



  • Do do you register the meta type with the call qRegisterMetaType("your custom meta type")?



  • Yes I tried with qRegisterMetaType, it didn't work either.



  • What's the (apparent) type of objVals?

    [quote]I have declared all the types with Q_DECLARE_METATYPE[/quote]

    Which types are you talking about exactly?

    [quote author="steno" date="1311784107"]Do do you register the meta type with the call qRegisterMetaType("your custom meta type")?[/quote]

    Not needed.



  • [quote author="steno" date="1311784107"]Do do you register the meta type with the call qRegisterMetaType("your custom meta type")?[/quote]

    Not needed.[/quote]

    Doh, true. Only needed for queued signals/slots and the property system.



  • For the sake of trying to pinpoint what happens: if you try to set a property by directly entering its name instead of retreiving it from your array, and then calling setProperty on the QObject* pointer, does that work?

    I mean: what happens if you use:
    @
    myQObjectPtr->setProperty('ThePropertyOfTheSubclass', QVariant("a value"));
    @



  • bq. peppe wrote:
    What’s the (apparent) type of objVals?

    The type of objVals is QObject** (array of QObject pointers).

    bq. peppe wrote:
    Which types are you talking about exactly?

    I have created my own classes, that inherit QObject. I'm registering the pointers to those classes.
    For example
    @class Class1 : public QObject {
    Q_OBJECT

    public:
    Class1() {
    }

    virtual ~Class1() {
    }
    

    };

    Q_DECLARE_METATYPE(Class1*)@

    Then I have another class Class2 containing a reference to Class1
    @class MyClass : public QObject {
    Q_OBJECT
    Q_PROPERTY (Class1* cl READ getCl WRITE setCl)
    Class1* cl;

    public:
    MyClass() {
    cl = NULL;
    }

    Class1* getCl() const {
        return cl;
    }
    void setCl(Class1 *obj) {
        cl = obj;
    }
    

    };@

    bq. Andre wrote:
    I mean: what happens if you use:
    @myQObjectPtr->setProperty('ThePropertyOfTheSubclass', QVariant("a value"));@

    It doesn't work either

    Here is a sample code that you can compile and run to troubleshoot the problem (Qt console application)

    main.cpp:
    @#include <QtCore/QCoreApplication>

    #include <iostream>
    #include "MyClasses.h"

    using namespace std;

    int main(int argc, char *argv[])
    {
    QCoreApplication a(argc, argv);

    MyClass mc;
    QObject* c = new Class1;
    
    QVariant value;
    value.setValue(c);
    
    if (mc.setProperty("cl",value) == false)
        cout<<"setProperty failed"<<endl;
    
    return a.exec&#40;&#41;;
    

    }
    @

    header file (MyClasses.h)
    @#ifndef MYCLASSES_H
    #define MYCLASSES_H

    #include <QObject>
    #include <QVariant>
    #include <QMetaObject>

    class Class1: public QObject {
    Q_OBJECT
    public:
    virtual ~Class1() {}
    };

    Q_DECLARE_METATYPE(Class1*)

    class MyClass: public QObject {
    Q_OBJECT
    Q_PROPERTY (Class1* cl READ getCl WRITE setCl)
    Class1* cl;

    public:
    MyClass() {
    cl = NULL;
    }

    Class1* getCl() const {
        return cl;
    }
    void setCl(Class1 *obj) {
        cl = obj;
    }
    
    virtual ~MyClass() {}
    

    };

    #endif // MYCLASSES_H
    @



  • No, that code is wrong -- the type of the QVariant is QObject*, which does not match the type of the property (Class1*). Therefore the setProperty will fail. Create your QVariant from a Class1* value and it will work.

    Yes, it's a kind of limitation of the whole QMetaType stuff...



  • Ok that's what I assumed, but I hoped there was something else.

    Thank you all for your help!



  • Oh, one last thing: why can't the QVariant of type QObject* be converted to a Class1* (using QVariant::convert(Type t))?

    Thanks



  • [quote author="genC" date="1311851619"]Oh, one last thing: why can't the QVariant of type QObject* be converted to a Class1* (using QVariant::convert(Type t))?[/quote]Because QVariant::type() returns 2 different type ids for Class1* and QObject*, and you can see in the source code of QVariant::canConvert(Type) that if the two type ids are different the functions returns false except for a few hard-coded conversions between Qt builtin types or between numeric types.

    But if it's really a composition and not an aggregation, you could just add the QObjects as children, and give them names (QObject::setObjectName) to find them later with yourContainerObject->findChild<Class1*>("yourObjectName");.



  • I see.
    Well in fact, I'm using both composition and aggregation, so QObjects as children might not really work for me...

    Thank you


Log in to reply