I'm trying to simplify (i.e. get rid of loads of boilerplate code) the creation of QObject
wrapper classes that forward property access of other QObject
derived classes.
To start small, I'm just trying it with one property:
// Sy_test.h - The wrapped class
class Sy_test : public QObject
{
Q_OBJECT
Q_PROPERTY( bool prop READ getProp WRITE setProp NOTIFY propChanged )
public:
Sy_test( QObject* parent = nullptr ) :
QObject{ parent },
prop_{ false } {}
bool getProp() const { return prop_; }
public slots:
void setProp( bool value )
{
if ( value != prop_ ) {
prop_ = value;
emit propChanged( prop_ );
}
}
signals:
void propChanged( bool value );
private:
bool prop_;
};
// Sy_proxy.h - The wrapper generator
#define SY_PROXYPROPERTY( Type, Name, Getter, Setter, Notifier )\
private:\
Q_PROPERTY( Type Name READ Getter WRITE Setter NOTIFY Notifier )\
\
public:\
Type Getter() const { return target_->Getter(); }\
\
public slots:\
void Setter( Type value ) { target_->Setter( value ); }\
\
signals:\
void Notifier( Type value );\
\
private:\
void setConnection()\
{\
connect( target_, &std::remove_pointer< decltype( target_ ) >::type::Notifier,\
this, &std::remove_pointer< decltype( this ) >::type::Notifier );\
}
#define SY_PROXY( ProxyName, TargetType, Prop1 )\
class ProxyName : public QObject\
{\
Q_OBJECT \
Prop1 \
\
public:\
ProxyName( TargetType* target ) :\
target_{ target }\
{\
setConnection();\
}\
\
virtual ~ProxyName() {}\
\
private:\
TargetType* target_;\
};
// This should create a Sy_test wrapper class called Sy_testProxy
SY_PROXY( Sy_testProxy,
Sy_test,
SY_PROXYPROPERTY( bool, prop, getProp, setProp, propChanged ) )
So the SY_PROXY
macro should create a class called Sy_testProxy
that carries a copy of the Sy_test::prop
property with implementations that just forward requests/signals.
And it almost does. Looking at the post-preprocessor output (I'm using g++, so the .ii files), I can see the Sy_testProxy
class is built and it's of the same form as the Sy_test
class. However, I get an error:
../CppTest/Sy_proxy.h:47: Error: NOTIFY signal 'propChanged' of property 'prop' does not exist in class Sy_testProxy.
make: *** [moc_Sy_proxy.cpp] Error 1
So it looks like the moc
is failing to parse my macro magic; although I'm not sure where as clearly the SY_PROXY
macro is present (the error is coming from a class called Sy_testProxy
), and SY_PROXYPROPERTY
must be valid too (as the moc
must have read the Q_PROPERTY
macro from it). Can anyone see where I've gone wrong?
For the record: I hate macros like everyone else, but I've fell into using them due to the moc
's aversion to templates and QObject
virtual inheritance. This investigation was triggered because I had a collection of instances performing heavy calculations in a separate thread, but they drive QML representations. However QML does not allow connections/property bindings to objects outside of the main thread, so I've been forced into creating proxy object that live in the main thread. If anyone has a better idea, I'm very open to them!