__property或者 [property]那样的非标准编译器特征。我们的解决方案可以在我们支持的每一个平台上和 任何标准的C++编译器一起工作。它基于元对象系统,元对象系统也通过 信号和槽提供对象通讯。
Q_PROPERTY宏声明了一个属性。属性只能在继承于 QObject的子类中声明。第二个宏, Q_OVERRIDE,可以用来覆盖一些子类中由继承得到的属性。
对于外面的世界,属性看起来和一个数据成员非常类似。然而,属性和普通的数据成员还是有一下一些不同点:
- 一个写函数。这个是可选的:像QWidget::isDesktop()这样的只读的属性就没有写函数。
- “存储”特征需要说明持续性。绝大多数属性是被存储的,但是有一小部分的虚拟属性却不用。举个例子,QWidget::minimumWidth()是不用存储的,因为它只是QWidget::minimumSize()的一种查看,没有自己的数据。
- 一个复位函数用来把属性设置回它根据上下文的特定缺省值。这个用法还是比较罕见的,但是举个例子,QWidget::font()需要这个函数,因为没有调用QWidget::setFont()意味着“复位到根据上下文特定的字体”。
- “可设计”特征说明它是否可以被一个图形用户界面生成器(例如Qt设计器)设置属性。对于大多数属性都有这个特征,但不是所有,例如QButton::isDown()。用户可以按按钮,并且应用程序设计人员可以让程序来按它自己的按钮,但是一个图形用户界面设计工具不能按按钮。
读、写和复位函数就像任何成员函数一样,继承或不继承,虚或不虚。只有一个例外就是,在多重继承的情况下,成员函数必须从第一个被继承类继承。
属性可以在不知道被使用的类的任何情况的时候通过 QObject中的一般函数进行读写。下面两个函数调用是等效的:
// QButton *b和QObject *o指向同一个按钮
b->setDown( TRUE );
o->setProperty( "down", TRUE );
等效的是指,除了第一个函数要快一些,在编译的时候提供了更好的诊断信息。在实际应用中,第一个函数更好些。然而,因为我们可以通过 QMetaObject获得任何一个QObject的所有有用属性的一个列表, QObject::setProperty()可以让你控制类中那些在编译时不可用的属性。
像 QObject::setProperty()一样,还有一个相应的 QObject::property()函数。 QMetaObject::propertyNames()返回所有可用属性的名称。 QMetaObject::property()返回一个指定属性的属性数据:一个 QMetaProperty对象。
这里有一个简单的例子说明了可以应用的绝大多数重要属性函数:
class MyClass : public QObject {Q_OBJECT public: MyClass( QObject * parent=0, const char * name=0 ); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; void setPriority( Priority ); Priority priority() const; };
这个类有一个名为“priority”的还不被 元对象系统所知的属性。为了让这个属性被元对象系统知道,你必须用 Q_PROPERTY宏来声明它。声明语法如下:
Q_PROPERTY( type name READ getFunction [WRITE setFunction]
[RESET resetFunction] [DESIGNABLE bool]
[SCRIPTABLE bool] [STORED bool] )
为了声明是有效的,读函数必须是常量函数并且返回值的类型是它本身或者是指向它的指针,或者是它的一个引用。可选的写函数必须返回void并且必须带有一个正确的参数,类型必须是它本身或者是指向它的指针,或者是它的一个常量引用。元对象编译器强迫这样的。
属性的类型可以是任何一个 QVariant支持的类型或者是一个自己在类中已经定义的枚举类型。因为 MyClass中的属性使用了枚举类型 Priority,这个类型必须也向属性系统注册。这样的话,像如下方式通过名称来设置值是可行的:
obj->setProperty( "priority", "VeryHigh" );
Q_ENUMS宏来进行注册。这里是一个包含属性相关声明的最终的类声明:
class MyClass : public QObject { Q_OBJECT Q_PROPERTY( Priority priority READ priority WRITE setPriority ) Q_ENUMS( Priority ) public: MyClass( QObject * parent=0, const char * name=0 ); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; void setPriority( Priority ); Priority priority() const; };
Q_SETS。像 Q_ENUMS一样,它注册了一个枚举类型,但是它额外的加了一个“set”的标记,也就是说,这个枚举数据可以被一起读或写。一个输入输出类也许有枚举数据“读”和“写”和接收“读|写”:这时最好用 Q_SETS来声明一个枚举类型,而不是 Q_ENUMS。
Q_PROPERTY段剩余的关键字是 RESET、 DESIGNABLE、 SCRIPTABLE和STORED。
RESET指定一个函数可以设置属性到缺省状态(这个缺省状态可能和初始状态不同)。这个函数必须返回void并且不带有参数。
DESIGNABLE声明这个属性是否适合被一个图形用户界名设计工具修改。缺省的 TRUE是说这个属性可写,否则就是 FALSE说明不能。你可以定义一个布尔成员函数来替代 TRUE或 FALSE。
SCRIPTABLE声明这个属性是否适合被一个脚本引擎访问。缺省是 TRUE,可以。你可以定义一个布尔成员函数来替代 TRUE或 FALSE。
STORED声明这个属性的值是否必须作为一个存储的对象状态而被记得。STORED只对可写的属性有意义。缺省是 TRUE。技术上多余的属性(比如,如果 QRect的geometry已经是一个属性了的 QPoint的pos)定义为 FALSE。
连接到属性系统是一个附加宏,“Q_CLASSINFO”,它可以用来把名称/值这样一套的属性添加到一个类的元对象中,例如:
Q_CLASSINFO( "Version", "3.0.0" )
和其它元数据一样,类信息在运行时是可以通过元对象访问的,具体请看 QMetaObject::classInfo()。
转载于:https://blog.51cto.com/dxwang/117874