Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C++ 使用宏创建QObject派生类_C++_Qt_Macros_C Preprocessor_Moc - Fatal编程技术网

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 );\