July 27, 2011

genC genC
Lab Rat
14 posts

[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

  1. 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

  1. MyClass mc;
  2. for (int i = 0; i < numObjFields; ++i) {
  3.     QVariant value;
  4.     value.setValue(objVals[i]);
  5.     mc.setProperty(fieldNames[i],value);
  6. }

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)

  1. MyClass mc;
  2. for (int i = 0; i < numObjFields; ++i) {
  3.     QVariant value;
  4.     value.setValue((trueType*)objVals[i]);
  5.     mc.setProperty(fieldNames[i],value);
  6. }

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!

11 replies

July 27, 2011

steno steno
Ant Farmer
133 posts

Do do you register the meta type with the call qRegisterMetaType(“your custom meta type”)?

July 27, 2011

genC genC
Lab Rat
14 posts

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

July 27, 2011

peppe peppe
Ant Farmer
1025 posts

What’s the (apparent) type of objVals?

I have declared all the types with Q_DECLARE_METATYPE

Which types are you talking about exactly?

steno wrote:
Do do you register the meta type with the call qRegisterMetaType(“your custom meta type”)?

Not needed.

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

July 27, 2011

steno steno
Ant Farmer
133 posts
steno wrote:
Do do you register the meta type with the call qRegisterMetaType(“your custom meta type”)?

Not needed.

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

July 28, 2011

Andre Andre
Area 51 Engineer
6031 posts

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:

  1. myQObjectPtr->setProperty('ThePropertyOfTheSubclass', QVariant("a value"));

 Signature 

Looking for Qt developers to join our team @ i-Optics: https://qt-project.org/forums/viewthread/25393/

July 28, 2011

genC genC
Lab Rat
14 posts

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

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

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

  1. class Class1 : public QObject {
  2.     Q_OBJECT
  3.  
  4. public:
  5.     Class1() {
  6.     }
  7.  
  8.     virtual ~Class1() {
  9.     }
  10. };
  11.  
  12. Q_DECLARE_METATYPE(Class1*)

Then I have another class Class2 containing a reference to Class1

  1. class MyClass : public QObject {
  2.     Q_OBJECT
  3.     Q_PROPERTY (Class1* cl READ getCl WRITE setCl)
  4.     Class1* cl;
  5.  
  6. public:
  7.     MyClass() {
  8.         cl = NULL;
  9.     }
  10.  
  11.     Class1* getCl() const {
  12.         return cl;
  13.     }
  14.     void setCl(Class1 *obj) {
  15.         cl = obj;
  16.     }
  17. };

Andre wrote:
I mean: what happens if you use:

  1. 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:

  1. #include <QtCore/QCoreApplication>
  2.  
  3. #include <iostream>
  4. #include "MyClasses.h"
  5.  
  6. using namespace std;
  7.  
  8. int main(int argc, char *argv[])
  9. {
  10.     QCoreApplication a(argc, argv);
  11.  
  12.     MyClass mc;
  13.     QObject* c = new Class1;
  14.  
  15.     QVariant value;
  16.     value.setValue(c);
  17.  
  18.     if (mc.setProperty("cl",value) == false)
  19.         cout<<"setProperty failed"<<endl;
  20.  
  21.     return a.exec();
  22. }

header file (MyClasses.h)

  1. #ifndef MYCLASSES_H
  2. #define MYCLASSES_H
  3.  
  4. #include <QObject>
  5. #include <QVariant>
  6. #include <QMetaObject>
  7.  
  8. class Class1: public QObject {
  9.     Q_OBJECT
  10. public:
  11.     virtual ~Class1() {}
  12. };
  13.  
  14. Q_DECLARE_METATYPE(Class1*)
  15.  
  16. class MyClass: public QObject {
  17.     Q_OBJECT
  18.     Q_PROPERTY (Class1* cl READ getCl WRITE setCl)
  19.     Class1* cl;
  20.  
  21. public:
  22.     MyClass() {
  23.         cl = NULL;
  24.     }
  25.  
  26.     Class1* getCl() const {
  27.         return cl;
  28.     }
  29.     void setCl(Class1 *obj) {
  30.         cl = obj;
  31.     }
  32.  
  33.     virtual ~MyClass() {}
  34. };
  35.  
  36. #endif // MYCLASSES_H

July 28, 2011

peppe peppe
Ant Farmer
1025 posts

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…

 Signature 

Software Engineer
KDAB (UK) Ltd., a KDAB Group company

July 28, 2011

genC genC
Lab Rat
14 posts

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

Thank you all for your help!

July 28, 2011

genC genC
Lab Rat
14 posts

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

Thanks

July 29, 2011

alexisdm alexisdm
Ant Farmer
123 posts

genC wrote:
Oh, one last thing: why can’t the QVariant of type QObject* be converted to a Class1* (using QVariant::convert(Type t))?
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”);.

July 29, 2011

genC genC
Lab Rat
14 posts

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

Thank you

 
  ‹‹ Problem with thread      Sending Signals to Non-Qt-Thread - How? ››

You must log in to post a reply. Not a member yet? Register here!