Qt属性系统

The Property System

Qt提供一个类似于其他编译器供应商提供的精致的属性系统。然而,作为一个编译器和平台独立的库,Qt并不依赖于非标准编译器特性,如__property 或 [property]。Qt解决方案能在支持Qt的平台上与任何标准C++编译器一起工作。它依赖于 Meta-Object System 。

Requirements for DeclaringProperties

要声明一个属性,在继承Qobject的类中用 Q_PROPERTY()宏。

Q_PROPERTY(type name

READ getFunction

[WRITE setFunction]

[RESET resetFunction]

[NOTIFY notifySignal]

[REVISION int]

[DESIGNABLE bool]

[SCRIPTABLE bool]

[STORED bool]

[USER bool]

[CONSTANT]

[FINAL])

以下是摘自 QWidget类的典型的属性声明:

Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)

属性的行为跟数据成员一样,但是它有通过Meta-Object System.的额外特性。

·         需要有READ 函数.用来读取属性的值. 理想的,为此最好是const函数 ,必须返回属性的类型或者属性类型一个指针或引用 , QWidget::focus 是只读属性, 读取函数QWidget::hasFocus().

·         WRITE 函数是可选的.它用来设置属性值.。它必须返回void和带一个参数,参数为属性的类型或者类型的引用或指针。如 QWidget::enabled有一个  WRITE 函数QWidget::setEnabled().。只读属性不需要有WRITE 函数,如 QWidget::focus没有WRITE 函数。

·         RESET函数也是可选的。它用来设置属性值为上下文指定的默认值。 QWidget::cursor有典型的 READ 和 WRITE 函数, QWidget::cursor() 和 QWidget::setCursor(), 并且它有 RESET 函数,QWidget::unsetCursor(),。因为没有调用QWidget::setCursor() 可以设置,上下文指定的光标。RESET函数必须返回void和不带参数。

·        NOTIFY 信号是可选的。如果定义,它指定为类中已经存在的信号,如果属性值发生变化则发出该信号。

·        REVISION 数是可选的。如果包含,它定义了属性和它的通知信号,被用在特定的公开给QML的API版本。

·        DESIGNABLE 属性指明在属性编辑的GUI设计工具是否可见。大多数属性是DESIGNABLE (默认true),取代true或false,你可以指定一个布尔成员函数。

·        SCRIPTABLE 属性指示脚本引擎是否可以访问该属性(默认true)。取代true或false,你可以指定一个布尔成员函数。

·        STORED 属性指示属性是否应该认为是自身有的还是依赖于其他值的,也指明了当存储对象的状态是必须保存属性值。大部分的属性是STORED (默认true),但是QWidget::minimumWidth() 的STORED 是false,因为它的值是从属性 QWidget::minimumSize(), 取得的。

USER属性指示属性是否认定为面向用户或用户可用编辑的。通常,每个类只有一个USER属性,如对于按钮 QAbstractButton::checked是用户可编辑的属性。注意: QItemDelegate 获取和设置widget 的 USER 属性。

·        CONSTANT 属性指明属性值是常量。对于给定的对象实例,READ 函数每次调用返回的值是一样的。不同的对象实例的常量值可能不一样,常量属性不能有 WRITE 函数 NOTIFY 信号。

FINAL属性指明.属性不能被子类重写。在某些情况下可以用于性能优化,但是moc并不强制进行。小心不能重写FINAL 属性。

READWRITE, 和 RESET 函数可以被继承,也可以是虚函数。如果是在多继承的类,它们必须是来自第一个被继承的类。

属性类型是QVariant支持的任意类型,也可以是用户自定义类型。在这个例子中,QDate类被当成是自定义类型。

Q_PROPERTY(QDate date READ getDate WRITE setDate)

由于QDate是用户自定义的,在声明属性时必须包含头文件<QDate>。

对于 QMapQList,和QValueList属性,属性的值是一个包含整个list或map的QVariant。注意:Q_PROPERTY 字符串不能包含逗号,因为逗号分割了宏参数。因此,你必须用Qmap替代 QMap<QString,QVariant>做属性类型。一致的,用 QList 和QvalueList取代QList<QVariant> 和 QValueList<QVariant>.。

Reading and WritingProperties with the Meta-Object System

可以用同用的函数 QObject::property()和QObject::setProperty(),来读写属性。除了属性的名称以为不用知道类的其他信息。下面的代码段,调用QAbstractButton::setDown() 和QObject::setProperty()都是设置"down"属性。

QPushButton*button =new QPushButton;
QObject*object = button;
 
button->setDown(true);
object->setProperty("down",true);

用 WRITE函数访问属性是最好的,因为.它更快而且编译时更好判断,但是用这种方法设置属性你需要知道运行时中的类。通过属性名称访问属性使你可以访问在运行时不知道的类。你可以通过查询 它的 QObjectQMetaObject, 和 QMetaProperties.获取类在运行时的属性。

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() 用来获取位置类中定义的每个属性的元数据。从元数据中获取属性名并传给QObject::property() 以获得当前对象的该属性的值。

A Simple Example

假定我们有一个类MyClass ,它继承了 QObject 并在private段声明了 Q_OBJECT 宏。我们想在MyClass中声明一个属性来跟着一个优先级值。属性名为priority,它的类型为在 MyClass 定义的枚举Priority,类型。

我们用Q_PROPERTY()宏在private段声明该属性, READ函数为 priorityWRITE 函数为 setPriority. 。枚举类型必须用 Q_ENUMS()宏进行注册。注册一个枚举类型使得枚举类型名对于 QObject::setProperty().调用是有效的。我们必须为 READ and WRITE函数提供自己的声明。MyClass 的声明可能如下:

class MyClass : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged)
    Q_ENUMS(Priority)
 
public:
    MyClass(QObject *parent =0);
    ~MyClass();
 
    enum Priority { High, Low, VeryHigh, VeryLow };
 
    void setPriority(Priority priority)
    {
        m_priority = priority;
        emit priorityChanged(priority);
    }
    Priority priority() const
    { return m_priority; }
 
signals:
    void priorityChanged(Priority);
 
private:
    Priority m_priority;
};

READ 函数是const并且返回属性的类型,WRITE 返回void并带有属性类型的一个参数。元对象编译器执行这些要求。

给定一个指向MyClass 对象的指针或者一个指向MyClass 实例的QObject 指针,我们有两种方法设置它的属性:

MyClass *myinstance =new MyClass;
QObject*object = myinstance;
 
myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority","VeryHigh");

在例子中,在MyClass 中定义并用 Q_ENUMS()注册的枚举类型是属性的类型,这使得枚举值在 setProperty()调用中是有效的字符串。如果枚举类型在另外的类中声明,则需要它的完全限定名,而且那个类必须继承 QObject和用 Q_ENUMS() 宏注册枚举类型。

一个类似的宏, Q_FLAGS(),。跟Q_ENUMS(),宏一样,它注册一个枚举类型,但是它标记类型为一组标记,值可以用OR操作。一个IO类可能有Read 和 Write枚举值, QObject::setProperty() 可以接收 Read | Write.。应该用 Q_FLAGS() 注册该枚举值。

Dynamic Properties

QObject::setProperty() 也可以用来为运行时的类实例添加新的属性。当用一个name 和value调用该函数,如果给定的name属性存在于QObject,中而且给定的value值与属性的类型兼容,则value被存储到属性中并返回true。如果value和属性的类型不兼容,属性的值不变并返回false。但是如果给定的name属性不存在于QObject中,则新的属性name和值value被自动添加到QObject,但是依旧返回false。这意味着返回false不能用来确定特定的属性是否被设置,除非你事先知道属性存在于QObject

注意:dynamic 属性被添加到每个实例的根,它们被添加到 QObject而不是QMetaObject.。通过该QObject::setProperty()传一个属性名和非法的QVariant值可以掉一个实例属性。 QVariant的默认构造函数构造一个非法的值。

Q_PROPERTY()声明的属性一样,Dynamic 属性可以用 QObject::property(),进行查询。

Properties and CustomTypes

属性类型是自定义类型的需要用Q_DECLARE_METATYPE()宏注册以使自定义类型的值可以存储在一个 QVariant对象中。这使得它们适合用于Q_PROPERTY()宏声明的静态属性和运行时创建的属性。

Adding AdditionalInformation to a Class

Q_CLASSINFO()是连接到属性系统的额外的宏,它可以添加额外的name--value 信息到类的元数据,如:

Q_CLASSINFO("Version","3.0.0")

和其他元数据一样,类信息也可以通过运行时的元数据对象获取。

http://blog.csdn.net/hai200501019/article/details/9204215

时间: 2024-10-25 18:24:28

Qt属性系统的相关文章

Qt属性系统(Qt Property System)

Qt提供了巧妙的属性系统,它与某些编译器支持的属性系统相似.然而,作为平台和编译器无关的库,Qt不能够依赖于那些非标准的编译器特性,比如__property 或者 [property].Qt的解决方案能够被任何Qt支持的平台下的标准C++编译器支持.它依赖于元对象系统(Meta_Object Sytstem),元对象系统通过信号和槽提供了对象间通讯的机制. 怎样声明属性 QObject的子类的私有域中使用Q_PROPERTY宏来声明一个属性 Q_PROPERTY(type name (READ 

[Qt入门篇]5 Qt的属性系统——声明属性

[Qt入门篇]5 Qt的属性系统--声明属性 Qt提供了灵活的属性系统,它基于Qt的元对象系统,不依赖于编译器,这保证了Qt独立于编译其和平台的特点.这篇文章主要看看如何声明属性. 属性系统比较复杂,先看一个简单的例子.在QWidget中,有很多属性的声明,找一个简单学习: Q_PROPERTY(boolmodalREADisModal) 这里出现了5个元素:Q_PROPERTY.bool.modal.READ.isModal.这五个元素都是啥作用呢? Q_PROPERTY:用于声明属性的宏:

[Qt入门篇]6 Qt的属性系统——READ/WRITE/MEMBER

在上一篇文章中,介绍了Qt属性的声明过程,本文主要介绍Q_PROPERTY()中可以使用的关键字. 在Qt5.6中,Q_PROPERTY()总共有12个关键字,本文介绍三个:READ.WRITE和MEMBER.为什么首先这三个?因为一个属性必须有一个读操作,如果没有READ定义,就必须定义MEMBER,否则这个属性无法访问,一个无法访问的属性又有什么意义呢?而WRITE则是与READ相关的操作,它是可选的. READ fun:定义了读取属性的接口fun,fun必须返回属性的类型或者属性同类型引用

深度探索QT窗口系统(五篇)

窗口作为界面编程中最重要的部分,没有窗口就没有界面,是窗口让我们摆脱了DOS时代,按钮是一个窗口,文本框是一个窗口,标签页是一个窗口,...一个窗口可以由多个窗口组成,每天我们都在与窗口打交道,当你打开windows时,桌面就是一个窗口,你打开浏览器时,你也正在访问窗口...好了,回到今天的话题,QT窗口系统,QT是一个跨平台的框架,类似微软的MFC,Borland的OWL,前者只适用于windows,而使用QT你可以开发windows平台应用程序,你也可以开发linux应用程序,当然了你也可以

QT开发(十四)——QT绘图系统

QT开发(十四)--QT绘图系统 一.QT绘图原理 Qt4中的2D绘图系统称为Arthur绘图系统,可以使用相同的API在屏幕上和绘图设备上进行绘制,主要基于QPainter.QPainterDevice和 QPainterEngine.QPainter执行绘图操作,QPainterDevice提供绘图设备,是一个二维空间的抽象,QPainterEngine提供一些接口.QPainter用来执行具体的绘图相关操作,如画点,画线,填充,变换,alpha通道等.QPaintDevice类是能够进行绘

QT绘制系统简介

#3个类:QPainter,QPainterDevice 和 QPaintEngine 三个类 #qpainter用于执行绘制操作 #QPainterDevice是一个二维空间抽象,允许qpainter在其上面进行绘制,也就是qpainter工作空间 #QPaintEngine 提供了画笔(qpainter)在不同设备上进行绘制统一接口,QPaintEngine类应用于QPainter和QPaintDevice 之间,如果需要自定义一个设备时 #则不需要关心QPaintEngine 这个类的QP

Qt Resource系统概说

什么是Qt Resource系统?简单的说,就是在可执行程序中存储binary文件,而且还是与平台无关的. 与Qt Resource系统密切相关的有三个法宝,分别是qmake.rcc.QFile. qmake是一种编译工具,根据developer创建的工程文件,自动生成MakeFile,简化了编译过程.qmake提供了moc和uic编译规则,专门用来支持Qt开发,其中moc是Qt元对象编译器Meta Object Compiler,uic是Qt的UI编译器User InterfaceCompil

WPF - 属性系统 (4 of 4)

依赖项属性的重写 在基于C#的编程中,对属性的重写常常是一种行之有效的解决方案:在基类所提供的属性访问符实现不能满足当前要求的时候,我们就需要重新定义属性的访问符. 但对于依赖项属性而言,属性执行逻辑的重新定义并不能存在于CLR属性包装中:WPF内部对依赖项属性的实现要求依赖项属性的CLR包装实现仅仅调用GetValue()以及SetValue()属性,而不能提供其它的自定义逻辑.相反地,我们需要通过更改创建时所传入的元数据来指定自定义属性执行逻辑,甚至在某些更苛刻的要求下,如更改依赖项属性的类

WPF - 属性系统 (3 of 4)

依赖项属性元数据 在前面的章节中,我们已经介绍了WPF依赖项属性元数据中的两个组成:CoerceValueCallback回调以及PropertyChangedCallback.而在本节中,我们将对其它元数据属性进行讲解. 首先让我们来看看元数据对默认值的支持.在元数据的构造函数中,软件开发人员可以通过它的defaultValue参数指定该依赖项属性的默认值.如果在元数据中并没有指定依赖项属性的默认值,那么WPF属性系统会自动根据依赖项属性的类型为该依赖项属性指定一个默认值: private s