PDA

View Full Version : Pointers and Q_PROPERTY



andersin
28th February 2006, 01:52
Hi,

I want to configure objects that are encapsulated in other objects using a configuration file and a plugin architecture, so I do not know in advance which objects are contained within the object. Is it possible to do this using the QObject::property() function?

Example:


class BInterface {
public:
virtual ~BInterface() {}
virtual int foo() = 0;
};

class B : public QObject, public BInterface
{
Q_OBJECT
Q_PROPERTY(int b READ b WRITE setB );
public:
virtual ~B() {}
virtual int foo() { return mv_b; }
const int b() const { return mv_b; }
void setB( const int b ) { mv_b = b; }
private:
int mv_b;
};

class A : public QObject{
Q_OBJECT
Q_PROPERTY(BInterface* B READ B WRITE setB);
public:
A() { mv_B = NULL; }
virtual ~A() { if(mv_B) delete mv_B; }
const BInterface * B() { return mv_B; }
void setB( const BInterface * B ) { if (mv_B) delete mv_B; mv_B = B; }
private:
BInterface * mv_B;
};


what I want to do is something like:


QObject * objA = new A();
BInterface* b = a.property("B");
b.setProperty("b", someValue);

can this be done at all?

jacek
28th February 2006, 16:16
can this be done at all?
To some extent:
#include <QtDebug>

#include <QCoreApplication>
#include <QObject>
#include <QVariant>

class BInterface
{
public:
virtual int foo() = 0;
};

class B : public QObject, public BInterface
{
Q_OBJECT
Q_PROPERTY( int b READ b WRITE setB )
public:

virtual int foo() { return mv_b; }

const int b() const { return mv_b; }
void setB( int b ) { mv_b = b; }

private:
int mv_b;
};

class A : public QObject
{
Q_OBJECT
Q_PROPERTY( QObject* B READ B WRITE setB )
public:
A( QObject *b = 0 ) : mv_B( b ) {}
virtual ~A() { if(mv_B) delete mv_B; }
QObject * B() { return mv_B; }
void setB( QObject* B ) { if (mv_B) delete mv_B; mv_B = B; }

private:
QObject* mv_B;
};

int main( int argc, char **argv )
{
QCoreApplication app( argc, argv );

QObject *a = new A( new B() );

// QObject *a = new A();
// a->setProperty( "B", 0 ); // works

// QObject *a = new A();
// a->setProperty( "B", new B() ); // crashes

QObject* b1 = a->property( "B" ).value< QObject *>();
if( b1 != 0 ) {
b1->setProperty( "b", 1234 );
}
else {
qDebug() << "b1 is null";
}

QObject* b2 = a->property( "B" ).value< QObject *>();
if( b2 != 0 ) {
qDebug() << b2->property( "b" );
}
else {
qDebug() << "b2 is null";
}

return 0;
}

#include "main.moc"

Output:
$ ./properties
QVariant(int, 1234)

andersin
1st March 2006, 00:39
Ok, that creates a workaround. The problem there is that I lose the type information of the property that I want to set.

I want to write plugins, so I am forced to use QObject and the meta object. I hoped that I could use const char * QMetaProperty::typeName together with void QObject::inherits(const char*) to check if I can use a particular plugin for the property. Like so:




// initialize the plugin loaders and all that jazz

QObject * pluginA = pluginLoaderForA.instance();
QObject * pluginB = pluginLoaderForB.instance();

const QMetaObject * mobjA = pluginA->metaObject;
QMetaProperty propA = mobj->property(mobj->indexOfProperty("B"));
QString typeName = QString(propA.typeName());
typeName.chop(1); //remove the * at the end
if ( pluginB.inherits(typeName.toAscii().constData()) ) {
// it inherits the object, so we can use it.
pluginA.setProperty("B", QVariant::fromValue(pluginB));
}



That is of course lost when I use QObject* as the type. On the other hand I am not sure if the setProperty still works. The object is still a QObject, but I doubt that the meta object stuff knows this.

Now one solution would probably be to inherit the interface from QObject, since then I know about the interface in the meta object system. It gets tricky with multiple inheritance of interfaces though, since the inheritance path to QObject is not unique any longer.

I guess I just need to provide the type of BInterface as a const char* property and force some naming scheme on the whole thing.

p.s.: I figured out that the crash in your code is due to some QVariant stuff. This is how I got that to work



// QObject *a = new A();
// a->setProperty( "B", new B() ); // crashes

QObject *a = new A();
a->setProperty("B", QVariant::fromValue(new B())); //works

jacek
1st March 2006, 15:05
OK, another try:
#include <QtDebug>

#include <QCoreApplication>
#include <QMetaProperty>
#include <QObject>
#include <QVariant>

class BInterface : public QObject
{
Q_OBJECT
public:
virtual int foo() = 0;
};

class B : public BInterface
{
Q_OBJECT
Q_PROPERTY( int b READ b WRITE setB )
public:

virtual int foo() { return mv_b; }

const int b() const { return mv_b; }
void setB( int b ) { mv_b = b; }

private:
int mv_b;
};

Q_DECLARE_METATYPE( BInterface* );

lass A : public QObject
{
Q_OBJECT
Q_PROPERTY( BInterface* B READ B WRITE setB )
public:
A( BInterface *b = 0 ) : mv_B( b ) {}
virtual ~A() { if(mv_B) delete mv_B; }

BInterface * B() { return mv_B; }
void setB( BInterface *B ) { if (mv_B) delete mv_B; mv_B = B; }

private:
BInterface* mv_B;
};

int main( int argc, char **argv )
{
QCoreApplication app( argc, argv );

QObject *a = new A();
BInterface * b = new B();
a->setProperty( "B", QVariant::fromValue( b ) );

const QMetaObject * metaObj = a->metaObject();
int index = metaObj->indexOfProperty( "B" );
if( index != -1 ) {
QMetaProperty prop = metaObj->property( index );
qDebug() << prop.typeName();
}
else {
qDebug() << "property not found";
}

BInterface *b1 = a->property( "B" ).value< BInterface *>();
if( b1 != 0 ) {
b1->setProperty( "b", 1234 );
}
else {
qDebug() << "b1 is null";
}

BInterface *b2 = a->property( "B" ).value< BInterface *>();
if( b2 != 0 ) {
qDebug() << b2->property( "b" );
}
else {
qDebug() << "b2 is null";
}

return 0;
}

#include "main.moc"

Output:
$ ./properties
BInterface*
QVariant(int, 1234)