@Andream
2017-07-16T03:51:25.000000Z
字数 3935
阅读 1370
Qt
在QObject的子类中,使用Q_PROPERTY声明一个Qt属性
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])
其中()括起来的是必选项,[]括起来的是可选项,|表示并列选项
以QWiget中的几个属性为例:
Q_PROPERTY(bool focus READ hasFocus)Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)
使用MEMBER关键字,将类的成员变量绑定为Qt属性
使用NOTIFY关键字,添加Qt属性的监听函数
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;
Qt属性表现得很像类的数据成员,它比普通的数据成员更牛逼的地方在于:它有Meta-Object System的支持,加上Qt的一些宏定义,就可以很方便的实现一些新特性。
READ getter定义属性的读函数。这是必须定义的,除非你定义了MEMBER。且getter必须是type xxx() const;这样的函数
WRITE setter定义属性的写函数。这是可选的。且setter必须是void xxx(type t);这样的函数
MEMBER m将属性和数据成员联系起来。MEMBER和'READ'至少要定义一个。
RESET f将属性重置到默认值
NOTIFY signal为属性添加监听信号。监听信号需要自己定义,且只能含有一个与属性同类型的参数(或不含参数)。当属性值发生变化时,会触发该信号并将新值传入。
REVISION int指定在特定的API版本中才会触发signal,默认是0
DESIGNABLE bool指定该属性是否能在Qt Designer中修改。默认是true。你可以修改为false,甚至是一个返回bool类型的函数
SCRIPTABLE bool指定该属性能否被脚本引擎引用。默认是true。你可以修改为false,甚至是一个返回bool类型的函数
STORED bool指明该属性对应一个真实存储的值?还是只是一个计算值?默认是true,少数时候是false。比如QWidget::minimumWidth只是返回 QWidget::minimumSize.width,并没有独立存储,所以STORED定义为false。
USER bool指明该属性是否是面向用户的,能被用户修改的?默认是false,如QAbstractButton::checked就是true
CONSTANT表明该属性是常量。即READ只能返回一个常值,且不能有WRITE和NOTIFY关键字
另外,READ,WRITE,RESET绑定的函数可以从父类那里继承,也可以是虚函数(子类覆盖父类的实现)。如果是多继承,那只认第一个继承的父类。
属性不仅支持基础数据类型,也支持Qt的拓展类型和用户自定义类型。
使用原生的QObject::property() 和 QObject::setProperty()函数即可读写属性。你不需要了解对象的其他任何性质,只要知道属性的名字即可。
QPushButton *button = new QPushButton;QObject *object = button;button->setDown(true);object->setProperty("down", true);//这两种写法等效
这两种写法哪种好呢?为什么要费尽心思搞个Property出来?
第一种写法运行的快,而且能在编译期间检查错误,但这要求你在编译之前就清楚这个类的情况。
而第二种写法能在运行时获取到对象的属性,这两种写法各有优点。
QObject *object = ... //比如这是一个JSON对象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);...}
假设我们有个类MyClass,继承自QObject,定义了Q_OBJECT宏。现在我们想追踪MyClass的Priority的变化(Priority是MyClass的成员,枚举类型)
现在我们用Q_PROPERTY将priority定义为MyClass的Qt属性,加上READ,WRITE, NOTIFY关键字,另外用Q_ENUM注册一下Priority。
class MyClass : public QObject{Q_OBJECTQ_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)public:MyClass(QObject *parent = 0);~MyClass();enum Priority { High, Low, VeryHigh, VeryLow };Q_ENUM(Priority)void setPriority(Priority priority){m_priority = priority;emit priorityChanged(priority);}Priority priority() const{ return m_priority; }signals:void priorityChanged(Priority);private:Priority m_priority;};
getter必须是Priority xxx()const;, setter必须是void xxx(Priority p);,这些都会由meta-object compiler来检查。
现在用指针来对MyClass操作
MyClass *myinstance = new MyClass;QObject *object = myinstance;myinstance->setPriority(MyClass::VeryHigh);object->setProperty("priority", "VeryHigh");
我们注意到bool QObject::setProperty("@name", @value);会返回一个bool值,这个bool值用来做什么呢?
如果QObject中存在给定的名字叫@name、@value类型的值,该值就会存到属性里,且返回true。
如果没有@name这个值,或者值的类型不匹配(换言之,没有用Q_PROPERTY定义匹配的属性),那么这个值就不改变,且返回false。但这个时候,Qt会自动给这个对象添加一个valueType name的属性,这就叫动态属性。动态属性表现得就和在代码里用Q_PROPERTY声明的一样。
也就是说,可以通过setProperty的返回值来判断是否设置了某个属性。
注意,动态属性是添加到对象里,而不是添加到类里。换言之,是添加到QObject,而不是QMetaObject。
通过setProperty(name, value)传进一个当前没有声明的属性,可以动态添加属性。
另外,通过setProperty(name, QVariant())传进一个无效的QVariant,可以动态删除属性。
如果要把自定义类型的变量声明为属性,要先用Q_DECLARE_METATYPE()注册该类型,这样自定义类型才能被存储到QVariant中。之后的使用方法和普通类型就一样了。
前面说的属性都是和成员变量绑定的,实际上Qt还可以使用Q_CLASSINFO(name, value),给类添加静态属性。
Q_CLASSINFO("Version", "3.0.0")
和成员属性一样,静态属性也可以在运行时读取(但不能写)。
见QMetaObject::classInfo()
相关链接: Meta-Object System, Signals and Slots, Q_DECLARE_METATYPE(), QMetaType, and QVariant.