Qt The Property System 属性系统

Qt The Property System 属性系统

什么是属性系统?

属性系统可以理解为另一种访问类内部成员变量的接口。

或者这样理解,当我们使用Qt Designer时,会发现右侧会有很多属性,可以把属性系统与之挂钩,但是也有些许不同。

对于类中的成员变量,我们通常采用set接口来修改,通过get接口来获取,但是当我们不知道某个属性在哪个类中,或者不知道这个属性的具体名称,又或者不知道这个类的setget接口,我们就可以借助Qt的属性系统来完成。

现在想象这样一个类,你不知道它的细节,但是这个类的某些属性已经被属性系统记录下来,我们想要或者这个属性,或者想要更改这个属性,我们可以通过属性系统来间接获取这个属性,比如:

MyClass *myClass = new MyClass;
QObject *object = myClass;

QVarient var = object->property("propertyName");
object->setProperty("propertyName", value);

当然object并不是必须的,因为MyClass一定继承了QObject,只有继承自QObject才可以使用属性系统。

也可以写成这样:

MyClass *myClass = new MyClass;

QVarient var = myClass->property("propertyName");
myClass->setProperty("propertyName", value);

这样的好处就是我们并不知道他的setget方法,我们只需要知道这个类有这样一个属性叫做propertyName,就可以对其进行读取和修改。

这里使用了QVarient,可以先看做类似于JavaScript中的var,包罗万象的一个类,具体细节以后再说。

总而言之,通过属性系统我们可以不必在编程的时候去考虑那么多细节。

当然这样一个系统不会自动生成,需要在构建类的过程中进行某些操作,这也是我们这一篇文章的核心内容。

声明Qt属性的要求

想要使用属性系统,我们首先要通过Q_PROPERTY()宏在类中进行定义。

官方基础范式如下:

Q_PROPERTY(type name
           (READ getFunction [WRITE setFunction] |
            MEMBER memberName [(READ getFunction | WRITE setFunction)])
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [REVISION int]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL]
           [REQUIRED])

解释如下:

  • type name表示变量类型和变量名,指明将哪一个变量升级到属性系统。
  • READ用于指明通过哪个函数来获取属性值。
  • WRITE用于指明通过哪个函数来修改属性值。
  • MEMBER用于没有使用READ的情况,通过MEMBER可以不使用READWRITE就能对变量进行访问和修改,通常READWRITEMEMBER不同时使用。
  • RESET是可选的,用于指明通过哪个函数恢复到最初状态。
  • NOTIFY是可选的,用于指明当此属性被修改时应当发送的Signal,此处的信号必须只能有不大于0个参数,如果有参数则必须和属性同类型,信号将会携带修改后的属性发送给槽。但是由于MEMBER的存在,可能没有set函数,此时Qt会自动发送这个信号。
  • REVISION是可选的,为一个int类型。它定义在特定的API修改中使用的属性和信号notifier,通常为了暴露给QML(目前我也不是很清楚怎么用)。
  • DESIGNABLE是可选的,为一个bool类型,标识这个属性是否在GUI design中可见。
  • SCRIPTABLE是可选的,为一个bool类型,标识这个属性能否被脚本引擎访问。
  • STORED是可选的,为一个bool类型,标识这个属性是否独自存在或者依赖于其他值,也标识当保存对象状态时是否要保存这个属性。比如QWidget::minimumWidth()的这个值就是false
  • USER是可选的,为一个bool类型,标识这个属性是否面向用户或者能否被用户修改,通常一个类只有一个用户属性。
  • CONSTANT是可选的,带有CONSTANT的属性表示此属性时常量,是不可修改的。这也就是说,这个属性是不能有WRITENOTIFY的。
  • FINAL是可选的,带有FINAL的属性表示此属性不能被派生类重写,moc不会强制检查,所以我们在使用的时候一定要检查不要重写带有FINAL的属性。
  • REQUIRED是可选的,带有REQUIRED的属性表示此属性应该由类的用户设置,moc不会强制检查。这个范式主要用于QML

READWRITERESET可以被继承,也可以为虚函数。如果是多继承,它们必须是第一个继承类中的。

属性类型可以是任何QVariant支持的类型,也可以是用户定义类型,比如QData就是用户定义类型(用户定义类型其实就是并没有加入关键字,而是某些类的类型)。

用法

定义

例子摘自官网:

    Q_PROPERTY(QColor color MEMBER m_color NOTIFY colorChanged)
    Q_PROPERTY(qreal spacing MEMBER m_spacing NOTIFY spacingChanged)
    Q_PROPERTY(QString text MEMBER m_text NOTIFY textChanged)
    ...
signals:
    void colorChanged();
    void spacingChanged();
    void textChanged(const QString &newText);

private:
    QColor  m_color;
    qreal   m_spacing;
    QString m_text;

这个例子中没有使用READWRITE,因为这个类中并没有定义setget函数,所以使用了MEMBER来指明是具体哪一个成员变量被映射出去(具体用法之后试验)。

使用

在前面已经看过一个简单的使用的例子,这里说一种官网上介绍的特殊的例子。

当我们连属性名都不知道的时候,能否使用属性系统呢?答案是肯定的,Qt已经考虑了这个情况。

QObject *object = ...
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i=0; i<count; ++i) {
    QMetaProperty metaproperty = metaobject->property(i);
    const char *name = metaproperty.name();
    QVariant value = object->property(name);
    ...
}

这就相当于遍历属性系统中的属性,来找到我们需要的属性。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值