C++ 使用宏创建QObject派生类
我正试图简化(即摆脱大量样板代码)创建C++ 使用宏创建QObject派生类,c++,qt,macros,c-preprocessor,moc,C++,Qt,Macros,C Preprocessor,Moc,我正试图简化(即摆脱大量样板代码)创建QObject包装类,这些包装类转发其他QObject派生类的属性访问 从小事做起,我只是试着用一个属性: // 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( QO
QObject
包装类,这些包装类转发其他QObject
派生类的属性访问
从小事做起,我只是试着用一个属性:
// 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 ) )
所以看起来moc
无法解析我的宏魔术;虽然我不确定SY_PROXY
宏在哪里出现(错误来自一个名为SY_testProxy
的类),并且SY_PROXYPROPERTY
也必须有效(因为moc
必须从中读取Q_属性
宏)。有人能看出我哪里出了错吗
作为记录:我和其他人一样讨厌宏,但由于
moc
对模板和QObject
虚拟继承的厌恶,我开始使用宏。之所以触发此调查,是因为我有一组实例在单独的线程中执行大量计算,但它们驱动QML表示。但是,QML不允许连接/属性绑定到主线程之外的对象,因此我被迫创建位于主线程中的代理对象。如果有人有更好的主意,我会很乐意接受的 除了moc
的变幻莫测之外,您的包装器不是线程安全的。未从正确的线程调用属性getter。所以我看不出包装有什么意义。您还可以直接从QML使用包装类,而不是包装器
为了线程安全,包装器应该缓存包装属性的值,以便总是从本地副本读取
在这一点上,您还可以编写一个完全动态的包装器,线程安全地转发包装对象的所有属性。使用元对象系统,您可以动态生成所有内容—属性值的副本等。就属性而言,您可以复制整个二进制描述符,因为包装器假装具有相同的属性。
moc
不太喜欢宏。它在某种程度上扩展了它们,但当它们变得复杂时,它就失败了
您可以尝试用public:
²替换signals:
(即手动展开signals
宏),并将Q\u signal
放在函数声明前面,告诉moc您希望函数成为一个信号
更换
signals:\
void Notifier( Type value );\
与
public:\
Q_SIGNAL void Notifier( Type value );\
⑨:对于复杂的。。。我不知道什么时候会失败,但我在过去遇到了一些不同的问题。根据我的经验,我猜想当一个宏体包含另一个宏时,moc会出现问题,如您的示例中的
signals
。但这只是一个猜测——也许宏moc在某些方面失败了。
²:在Qt 5之前,它曾经受到保护
。
有一段很好的代码,你可以在谷歌上搜索qmltricks,它有你需要的一切作为一个好的开始 你只需要一个标题。有一个扩展空间来支持只读属性或自定义getter/setter。。但我建议你去看看。我现在找不到一个原创的。页面,在上一次Qt峰会上看到了一个演示,你们可能可以查看Qt站点上的实际资料 在github上的链接下面,有几个可用的版本
我想这不会改变任何事情,但是你可以尝试
Q\u信号
而不是信号
。。。AFAIK moc不能很好地扩展宏。在某种程度上确实如此,但由于它不符合标准,我总是在QObject派生类的头中避免使用它们。你问题的第一段应该详细得多。请解释一下你到底想做什么。什么是类层次结构,什么对象具有什么属性,模板类在哪里,以及为什么需要这些。“记录”段落是其中的一部分,但仍然不能提供足够的信息。我也不确定您所说的“QML不允许连接/属性绑定到主线程之外的对象”。KubaOber试图连接/绑定/调用从QML到C++的代码> QObjult<代码>,在非主线程中运行,结果是“非法尝试连接到与QML引擎不同的线程中的________;”。@KubaOber我在多个线程中有QObject
派生类型,其中许多具有QML表示(即可以显示这些实例携带的数据的QML类型),但是,由于上述缺陷,我无法绑定到它们的任何属性-因此我在主线程中创建代理对象,以允许两者通信。Sy_test
只是用于试验宏的示例代码,不属于此线程安全,也不应该是。我已经编写了完全转发所有属性的代理,Q_可调用的
方法和公共插槽-但此练习的全部目的是减少与之相关的所有锅炉板。@cmannett85您需要一个可以从任何其他类转发的代理类。通用类:)好的,接受挑战。谢谢!我想知道如何使用宏生成信号,以及他显然没有办法做这件事。
public:\
Q_SIGNAL void Notifier( Type value );\