1、属性定义
在属性系统中,Qt提供了一个复杂的属性系统,与一些编译器供应商提供的类似。 然而,作为一个独立于编译器和平台的库,Qt不依赖于非标准的编译器特性,如__property或[property]。 Qt解决方案适用于Qt支持的每个平台上的任何标准c++编译器。 它基于元对象系统,元对象系统也通过信号和插槽提供对象间通信。
Q_PROPERTY() 是一个宏,用来在一个类中声明一个属性property,由于该宏是qt特有的,需要用moc进行编译,故必须继承于QObject类。
官方给的格式:
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])
然后官方给的简单的例子:
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;
官方给的对应属性:
- 如果没有指定MEMBER变量,则需要一个READ访问器函数。 它用于读取属性值。
理想情况下,const函数用于此目的,它必须返回属性的类型或对该类型的const引用。
例如,QWidget::focus是一个READ函数的只读属性,QWidget::hasFocus()。 - 一个可选的WRITE访问器函数。它用于设置属性的值。它必须返回空并且至少具有一个参数,参数是属性类型的值或指针或引用。例如:QWidget::enabled具有WRITE函数QWidget::setEnable()。只读属性不需要写函数。例如,QWidget::focus没有对应的写函数。
- 一个可选的RESET函数。用于设置属性的值到它的默认值。例如:QWidget::cursor具有典型的READ和WRITE函数,QWidget::cursor()和QWidget::setCursor(),并且它也具有一个RESET函数,QWidget::unsetCursor()。RESET函数必须返回void并且不带有任何参数。
- 一个可选的NOTIFY信号。如果被定义了,信号将在属性的值改变时发出。信号必须带有一个参数,这个参数的类型必须与属性相同;参数保存的是属性的新值。
- 一个DESIGNABLE变量表明此属性是否在界面设计器的属性编辑器中出现。大多数属性是可见的,除了为这个变量传入true或false,你还可以指定一个bool型的成员函数。
- SCRIPTABLE变量表明这个属性是否可以被一个脚本引擎操作(默认是true)。你也可以赋予它true或false或bool型函数。
- STORED变量表明了属性是否被认为是独立存在还是依赖于其它的值而存在。它也表明是否在保存对象状态时保存此属性的值。大多数属性都是需要保存的,但是,如QWidget::minimumWidth()就是不被保存的,因为它的值是从另一个属性QWidget::minimumSize()得来的。
- USER变量表明属性是否被设计为面向用户的或用户可修改的类属性。通常,每个类只有一个USER属性。例如,QAbstractButton::checked是按钮类的用户可修改属性。注意QItemDelegate获取和设置widget的USER属性。
- CONSTANT的出现表明属性的值是不变的。对于一个object实例,常量属性的READ方法在每次被调用时必须返回相同的值。此常量值可能在不同的object实例中不相同。一个常量属性不能具有WRITE方法或NOYIFY信号。
- FINAL变量的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不是被moc强制的。程序员必须永远注意不能重写一个FINAL属性。
2.动态属性
QObject::setProperty()也可以用来在运行时期向一个类的实例添加新的属性。当使用一个名字和值调用它时,如果QObject中一个指定名称的属性已经存在,并且如果给定的值与属性的类型兼容,那么,值就被存储到属性中,然后返回true。如果值与属性类型不兼容,属性的值就不会发生改变,会返回false。但是如果QObject中一个指定名称的属性不存在(例如:未用Q_PROPERTY()声明),一个带有指定名称和值的新属性就被自动添加到QObject中,但是依然会返回false。这意味着返回值不能用于确定一个属性是否被设置值,除非事先知道这个属性已经存在于QObject中。
注意:态属性被添加到每一个实例中,即:它们被添加到QObject中,而不是QMetaObject。一个属性可以从一个实例中删除,通过传入属性名和非法的QVariant值给QObject::setProperty()。默认的QVariant构造器会构造一个非法的QVariant。
动态属性可用QObject::property()来查询,就像使用Q_PROPERTY()声明的属性一样。
QPushButton *button = new QPushButton;
QObject *object = button;
object->setProperty("flat", true);
boo1 isFlat= object->property("flat");
3.属性和自定义类型
被属性使用的自定义类型需要使用Q_DECLARE_METATYPE()宏注册,以便它们的值能被保存在QVariant对象中。这使得它们适用于在类定义时使用Q_PROPERTY()宏声明的静态属性,以及运行时创建的动态属性。
4.为类添加附加信息
属性系统还有一个宏Q_CLASSINFO(),可以为类的元对象定义“名称–值”信息,例如:
class QMyClass : public QObject
{
Q_OBJECT
Q_CLASSINFO("author""Huang")
Q_CLASSINFO("company","UDP")
Q_CLASSINFO("version","3.2.1")
public:
...
}
用Q_CLASSINFO()宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如classInfo(int)获取某个附加信息,函数原型定义如下:
OMetaClassInfo OMetaObject::classInfo(int index) const
返回值是QMetaClassInfo 类型,有 name()和 value()两个函数可获得类附加信息的名称和值.