PDA

View Full Version : One set slot for multiple Q_PROPERTYs



fonzi337
21st February 2012, 23:32
Hi,

I'm trying to find a good solution for a maintenance problem I have with a class that declares a number of QString Q_PROPERTYs. Basically, I have five Q_PROPERTYs defined in a class each with their own set method for the WRITE. Each set method looks nearly identical: it calls a function Foo passing in the name of the property. Thus, I get something that looks like this:

MyClass.h:


MyClass : public QObject
{
Q_OBJECT

Q_PROPERTY(QString myProperty1 READ myProperty1 WRITE setMyProperty1 NOTIFY myProperty1Changed)
Q_PROPERTY(QString myProperty2 READ myProperty2 WRITE setMyProperty2 NOTIFY myProperty2Changed)
//...
};


MyClass.cpp:


void MyClass::setMyProperty1(QString arg)
{
Foo("myProperty1");
}

void MyClass::setMyProperty2(QString arg)
{
Foo("myProperty2");
}


I'd like some generic way to ensure that as I add new Q_PROPERTYs to this class that I don't have to keep defining these separate boiler-plate set methods.

One idea I have is to have all the properties map to the same set method, as shown below:

MyClass.h:


MyClass : public QObject
{
Q_OBJECT

Q_PROPERTY(QString myProperty1 READ myProperty1 WRITE setMyProperty NOTIFY myProperty1Changed)
Q_PROPERTY(QString myProperty2 READ myProperty2 WRITE setMyProperty NOTIFY myProperty2Changed)
//...
};


MyClass.cpp:


void MyClass::setMyProperty(QString arg)
{
Foo(/* What goes in here? */);
}


The problem I'm having is figuring out how to determine what particular Q_PROPERTY triggered the call to setMyProperty so I can call Foo supplying it with the correct string.

Does Qt provide any facilities to make this work in such a generic fashion?

Thanks!

fonzi337
23rd February 2012, 17:30
Any thoughts? I'm really not sure how to get around this issue. I thought about using the QObject::sender() to get information, but I don't think that tells me what property triggered the call to the set method.

Lykurg
23rd February 2012, 17:42
You can't. How should that go?

fonzi337
23rd February 2012, 19:15
So Qt doesn't provide functionality that allows me to know what property triggered a call to a certain set method? It seems like this would be useful for cutting down on a lot of similar code (particularly if you have a class that has dozens of Q_PROPERTYs).

MarekR22
23rd February 2012, 21:21
1st of all setter pattern should look like this:

void setSomeProp(const Type &x) {
if (propertyField != x) {
propertyField = x;
somePropChanged(x);
}
}
so you don't signal change when noting changes (this also prevents recursion in many cases).

2nd it is assumed that each property has own setter and getter so in coe you should know what property it is.
If you want save on retyping you can define macro:

#define DefStdSetterRef(_className_, _funcName_, _argType_, _propName_) \
void _className_::_funcName_(const _argType_ &x) { \
if (m##_propName_ != x) { \
m##_propName_ = x; \
_propName_##Changed(x); \
} \
}

fonzi337
23rd February 2012, 21:49
Thanks MarekR2. In this case, I'm not following the generic setter method structure, as Foo in my case actually forwards the property setting over a network to be handled elsewhere (of course, the generic setter method structure is used in the resulting method call on the receiving end).

You mentioned that "it is assumed that each property has own setter and getter." Is this just a coding convention or is this a requirement imposed by Qt? The macro you suggested does help, but it's still not as generic/clean of a solution as I am looking for (if one exists). I'd like to be able to only add a Q_PROPERTY in the .h file and not make any other method additions or changes to my .cpp file. This is what got me thinking about having all the Q_PROPERTYs in the class point to the same setter method. From a maintenance standpoint, this is cleaner and would cut down on redundant code, allowing all Q_PROPERTYs to be handled in a generic fashion. Is it safe to assume then that Qt does not provide the necessary information to make this scheme work (i.e., knowing what property change triggered the call to the setter method)?