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