Qt属性系统

来源:互联网 发布:站内优化 编辑:程序博客网 时间:2024/06/01 19:48

(本篇文章为Qt官网英文文章,此为翻译整理所作)

The Property System

    Qt提供了一套和其他通用编译器提供商所提供的属性系统类似的属性系统 然而,作为一个独立于编译器和平台的库,Qt不能依赖像__property或者[property]那样的非标准编译器特征。Qt的解决方案是在支持任意标准平台上的C++编译器的基础上进行工作。它基于元对象系统,元对象系统也通过信号和槽提供对象通讯。

 

一、声明属性

1、要求

    1)Q_PROPERTY() 宏进行声明;

    2)必须集成QObject()。

2、属性类别

Q_PROPERTY(type name

           READ getFunction

           [WRITE setFunction]

           [RESET resetFunction]

           [NOTIFY notifySignal]

           [REVISION int]

           [DESIGNABLE bool]

           [SCRIPTABLE bool]

           [STORED bool]

           [USER bool]

           [CONSTANT]

           [FINAL])

1)READ getFunction

    必须有的,用于读取属性,使用const限定,返回属性的类型或者类型的指针或引用。

2)WRITE setFunction

    可选的,用于设置属性,参数是一个属性的类型,或者属性的const指针或引用,返回值是void。

3)RESET resetFunction

    可选的,用于把属性根据上下文设置回它的特定缺省值,没有参数,返回void。

4)NOTIFY notifySignal

    可选的,当属性改变时发射的信号。

5)REVISION int

    可选的,定义属性和它的信号暴露给QML的修订版本。

6)DESIGNABLE bool

    该属性是否在Qt的QtDesigner设计器中显示,默认true即为显示。

7)SCRIPTABLE bool

    该属性是否可以通过脚本系统进行访问,默认true即为可访问。

8)STORED bool

    绝大多数属性是被存储的,但是有一小部分的虚拟属性却不用。举个例子,QWidget::minimumWidth()是不用存储的,因为它只是QWidget::minimumSize()的一种查看,没有自己的数据。

9)USER bool

    USER变量表明属性是否被设计为面向用户的或用户可修改的类属性。通常,每个类只有一个USER属性。例如,QAbstractButton::checked是按钮类的用户可修改属性。

10)CONSTANT

    CONSTANT的出现表明属性的值是不变的。对于一个object实例,常量属性的READ方法在每次被调用时必须返回相同的值。此常量值可能在不同的object实例中不相同。一个常量属性不能具有WRITE方法或NOYIFY信号。

11)FINAL

    FINAL变量的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不是被moc强制的。程序员必须永远注意不能重写一个FINAL属性。

READ,WRITE和RESET函数都可以被继承。它们也可以是虚函数。当它们在被多重继承中被继承时,它们必须出现在第一个被继承的类中。

3、类型的种类
    属性的类型可以是被QVariant支持的所有类型,也可以是用户定义的类型。自定义类型需要使用Q_DECLARE_METATYPE()宏注册,以使它们的值能被保存在QVariant对象中。

    对于QMap,QList和QValueList属性,属性的值是一个QVariant,它包含整个list或map。注意Q_PROPERTY字符串不能包含逗号,因为逗号会划分宏的参数。因此,你必须使用QMap作为属性的类型而不是QMap<QString,QVariant>。为了保持一致性,也需要用QList和QValueList而不是QList<QVariant>和QValueList<QVariant>。

4、属性读写方式

    一个属性可以使用常规函数QObject::property()和QObject::setProperty()进行读写,不用知道属性所在类的任何细节,除了属性的名字。在下面的小代码片段中,调用QAbstractButton::setDown()和QObject::setProperty()都把属性设置为“down”。

 

QPushButton *button = new QPushButton;  

QObject *object = button;  

button->setDown(true);  

object->setProperty("down", true);  

 

    通过WRITE操作器来操作一个属性是上面两者中更好的,因为它快并且在编译时给于更好的诊断帮助,但是以这种方式设置属性要求你必须在编译时了解其类。通过名字来操作属性使你可以操作在编译器你不了解的类。你可以在运行时发现一个类的属性们,通过查询它的QObject,QMetaObject和QMetaProerties。

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

    ...  

}  

 

    在上面的代码片段中,QMetaObject::property()被用于获取未知类中的属性的metadata。从metadata中获取属性名然后传给QObject::property()来获取

5、示例

    假设我们有一个类MyClass,它从QObject派生并且在它的private区使用 了Q_OBJECT宏。我们想在MyClass类中声明一个属性来持续追踪一个Priorty值。属性的值叫做priority,并且它的类型是一个在类MyClass中定义的叫做Priority的枚举。
    我们在类的private区使用Q_PROPERTY()来声明属性。READ函数叫做priority,并且我们包含一个WRITE函数叫做setPriority。枚举类型必须使用Q_ENUMS()注册到元数据对象系统中。注册一个枚举类型使得枚举的名字可以在调用QObject::setProperty()时使用。我们还必须为READ和WRITE函数提供我们自己的声明。MyClass的声明看起来应该是这样的:

class MyClass : public QObject  

{  

    Q_OBJECT  

    Q_PROPERTY(Priority priority READ priority WRITE setPriority)  

    Q_ENUMS(Priority)  

public:  

    MyClass(QObject *parent = 0);  

    ~MyClass();  

    enum Priority { High, Low, VeryHigh, VeryLow };  

    void setPriority(Priority priority);  

    Priority priority() const;  

};

    READ函数是const的并且返回属性的类型。WRITE函数返回void并且具有一个属性类型的参数。元数据对象编译器强制做这些事情。
    在有了一个指向MyClass实例的指针时,我们有两种方法来设置priority属性:

MyClass *myinstance = new MyClass;  

 QObject *object = myinstance;  

 myinstance->setPriority(MyClass::VeryHigh);  

 object->setProperty("priority", "VeryHigh");  

    在此例子中,枚举类型在MyClass中声明并被使用Q_ENUMS()注册到元数据对象系统中。这使得枚举值可以在调用setProperty()时做为字符串使用。如果枚举类型是在其它类中声明的,那么我们就需要用枚举的全名(如OtherClass::Priority),并且这个其它类也必须从QObject中派生并且也要注册枚举类型。
    另一个简单的Q_FLAGS()也是可用的。就像Q_ENUMS(),它注册一个枚举类型,但是它把枚举类型作为一个flag的集合,也就是,值可以用OR操作来合并。一个I/O类可能具有枚举值Read和Write并且QObject::setProperty()可以接受 Read|Write。此时应使用Q_FLAGS()来注册枚举值。

6、动态属性

    Qobject::setProperty()也可以用来在运行时向一个类的实例添加新的属性。当使用一个名字和值调用它时,如果一个对应的属性已经存在,并且如果值的类型与属性的类型兼容,那么值就被存储到属性中,然后返回true。如果值类型不兼容,属性的值就不会发生改变,就会返回false。但是如果对应名字的属性不存在,那么一个新的属性就诞生了,以传入的名字为名,以传入的值为值,但是依然会返回false。这表示返回值不能用于确定一个属性是否被设置值,除非你已经知道这个属性已经存在于QObject中了。
    注意动态属性被添加到单个实现的基础中,也就是,被添加到QObject,而不是QMetaObject。一个属性可以从一个实例中删除,通过传入属性的名字和非法的QVariant值给QObject::setProperty()。默认的QVariant构造器构造一个非法的QVariant。
    动态属性可用QObject::property()来查询,就行使用Q_PROPERTY()声明的属性一样。

通过自定义类型来构造Q_PROPERTY()的静态类型,这样可以被用以在动态类型中使用。

 

Qt官网链接:http://doc.qt.io/qt-4.8/properties.html

 


0 0
原创粉丝点击