一种避免样板代码来定义C 中QObject属性的方法(可以从QML访问)



QT文档包含此示例:

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
public:
    void setAuthor(const QString &a) {
        if (a != m_author) {
            m_author = a;
            emit authorChanged();
        }
    }
    QString author() const {
        return m_author;
    }
signals:
    void authorChanged();
private:
    QString m_author;
};

是否有一种方法可以避免写所有此类样板代码只是为了定义QML可交换属性?对我来说肮脏的工作并自动定义所有其余的?

注意:我在这里找到了一套漂亮的宏,但它不是QT的官方部分,所以我不确定它是否没有陷阱。

没有为此的标准解决方案,但是后来我在此问题上查看了这个问题,我发现qmltricks,我认为这真的很不错。

会员是一种方法,但是有时您可能需要更多地控制Setter/Getter方法中发生的事情,所以说实话,我不经常使用它。

我用一些附加的宏来制作了自己的子集,例如qobject对属性的支持,自定义设置器/getter等。

#define QOBJECT_CONSTANT_PROPERTY(typeName, propertyName, getterName, setterName) 
public: 
    Q_PROPERTY (typeName * propertyName READ getterName CONSTANT) 
protected: 
QPointer<typeName> m_##getterName; 
public: 
    typeName * getterName () const { 
    return m_##getterName; 
    } 
public Q_SLOTS: 
    bool setterName (typeName * newVal) { 
        bool ret = false; 
        if ((ret = m_##getterName != newVal)) { 
        m_##getterName = newVal; 
        } 
        return ret; 
    } 
public:

#define QOBJECT_WRITABLE_PROPERTY(typeName, propertyName, getterName, setterName, signalName) 
public: 
Q_PROPERTY(typeName * propertyName READ getterName WRITE setterName NOTIFY signalName) 
protected: 
QPointer<typeName>  m_##getterName; 
public: 
typeName * getterName() const { 
return m_##getterName; 
} 
public Q_SLOTS: 
bool setterName(typeName * newVal) { 
bool ret = false; 
if ((ret = (m_##getterName != newVal))) { 
m_##getterName = newVal; 
    emit signalName(#propertyName); 
} 
return ret; 
} 
Q_SIGNALS: 
void signalName(const char *); 
public:
#define QOBJECT_READONLY_PROPERTY(typeName, propertyName, getterName, setterName, signalName) 
public: 
    Q_PROPERTY (typeName * propertyName READ getterName NOTIFY signalName) 
protected: 
QPointer<typeName> m_##getterName; 
public: 
    typeName * getterName () const { 
    return m_##getterName; 
    } 
public Q_SLOTS: 
    bool setterName (typeName * newVal) { 
        bool ret = false; 
        if ((ret = (m_##getterName != newVal))) { 
        m_##getterName = newVal; 
        emit signalName (#propertyName); 
        } 
        return ret; 
    } 
 Q_SIGNALS: 
    void signalName (const char *); 
public:
#define WRITABLE_PROPERTY(typeName, propertyName, getterName, setterName, signalName) 
public: 
    Q_PROPERTY (typeName propertyName READ getterName WRITE setterName NOTIFY signalName) 
protected: 
typeName m_##getterName; 
public: 
    typeName getterName () const { 
    return m_##getterName; 
    } 
public Q_SLOTS: 
bool setterName (const typeName & newVal) { 
        bool ret = false; 
        if ((ret = (m_##getterName != const_cast<typeName&>(newVal)))) { 
        m_##getterName = newVal; 
        emit signalName (#propertyName); 
        } 
        return ret; 
    } 
Q_SIGNALS: 
void signalName ( const char * ); 
public:

#define WRITABLE_PROPERTY_USER_GETTER(typeName, propertyName, getterName, setterName, signalName) 
public: 
    Q_PROPERTY(typeName propertyName READ getterName WRITE setterName NOTIFY signalName) 
protected: 
typeName m_##getterName; 
    public Q_SLOTS: 
bool setterName(const typeName & newVal) { 
bool ret = false; 
if ((ret = (m_##getterName != const_cast<typeName&>(newVal)))) { 
    m_##getterName = newVal; 
    emit signalName(#propertyName); 
} 
    return ret; 
} 
Q_SIGNALS: 
void signalName(const char *); 
public:

#define WRITABLE_PROPERTY_USER_SETTER(typeName, propertyName, getterName, setterName, signalName) 
public: 
    Q_PROPERTY (typeName propertyName READ getterName WRITE setterName NOTIFY signalName) 
protected: 
typeName m_##getterName; 
public: 
    typeName getterName () const { 
    return m_##getterName; 
    } 
Q_SIGNALS: 
void signalName ( const char * ); 
public:


#define READONLY_PROPERTY(typeName, propertyName, getterName, setterName, signalName) 
public: 
    Q_PROPERTY (typeName propertyName READ getterName NOTIFY signalName) 
protected: 
typeName m_##getterName; 
public: 
    typeName getterName () const { 
    return m_##getterName; 
    } 
public Q_SLOTS: 
    bool setterName (const typeName & newVal) { 
        bool ret = false; 
        if ((ret = (m_##getterName != const_cast<typeName&>(newVal)))) { 
        m_##getterName = newVal; 
        emit signalName (#propertyName); 
        } 
        return ret; 
    } 
 Q_SIGNALS: 
    void signalName (const char *); 
public:

#define CONSTANT_PROPERTY(typeName, propertyName, getterName, setterName) 
public: 
    Q_PROPERTY (typeName propertyName READ getterName CONSTANT) 
protected: 
typeName m_##getterName; 
public: 
    typeName getterName () const { 
    return m_##getterName; 
    } 
public Q_SLOTS: 
    bool setterName (const typeName & newVal) { 
        bool ret = false; 
        if ((ret = m_##getterName != newVal)) { 
        m_##getterName = const_cast<typeName&>(newVal); 
        } 
        return ret; 
    } 
public:
#define LIST_PROPERTY(CLASS, NAME, TYPE) 
public: 
    static int NAME##_count (QQmlListProperty<TYPE> * prop) { 
        CLASS * instance = qobject_cast<CLASS *> (prop->object); 
        return (instance != NULL ? instance->m_##NAME.count () : 0); 
    } 
    static void NAME##_clear (QQmlListProperty<TYPE> * prop) { 
        CLASS * instance = qobject_cast<CLASS *> (prop->object); 
        if (instance != NULL) { 
            instance->m_##NAME.clear (); 
        } 
    } 
    static void NAME##_append (QQmlListProperty<TYPE> * prop, TYPE * obj) { 
        CLASS * instance = qobject_cast<CLASS *> (prop->object); 
        if (instance != NULL && obj != NULL) { 
            instance->m_##NAME.append (obj); 
        } 
    } 
    static TYPE * NAME##_at (QQmlListProperty<TYPE> * prop, int idx) { 
        CLASS * instance = qobject_cast<CLASS *> (prop->object); 
        return (instance != NULL ? instance->m_##NAME.at (idx) : NULL); 
    } 
    QList<TYPE *> get_##NAME##s (void) const { 
        return m_##NAME; 
    } 
private: 
    QList<TYPE *> m_##NAME;

如果使用MEMBER属性,则可以避免访问器功能的实现。然后,您只需要成员和可选的通知信号。

class Message : public QObject {
    Q_OBJECT
    Q_PROPERTY(QString author MEMBER m_author NOTIFY authorChanged)  
    QString m_author;
public:
    // ...
signals:
    void authorChanged();
};

宏观方法应该很好,但是您链接的方法有两个问题:

  • 获取不是const
  • 通知信号不应发射值

因此,使用MEMBER您可以进一步简化:

#define QPROP(type, name) 
  private: 
  Q_PROPERTY(type name MEMBER m_ ## name NOTIFY name ## Changed ) 
  type m_ ## name; 
  public: 
  Q_SIGNAL void name ## Changed();

,然后仅:

class Message : public QObject {
    Q_OBJECT
    QPROP(QString, author)
};

最新更新