这是用户在 2024-12-28 18:43 为 https://doc.qt.io/qt-5/properties.html 保存的双语快照页面,由 沉浸式翻译 提供双语支持。了解如何保存?

The Property System  属性系统

Qt provides a sophisticated property system similar to the ones supplied by some compiler vendors. However, as a compiler- and platform-independent library, Qt does not rely on non-standard compiler features like __property or [property]. The Qt solution works with any standard C++ compiler on every platform Qt supports. It is based on the Meta-Object System that also provides inter-object communication via signals and slots.
Qt 提供了一个与一些编译器厂商提供的类似的复杂属性系统。但是,作为一个与编译器和平台无关的库,Qt 不依赖于非标准的编译器特性,例如 __property[property] 。Qt 解决方案适用于 Qt 支持的任何平台上的任何标准 C++ 编译器。它基于元对象系统,该系统还通过信号和槽提供对象间通信。

Requirements for Declaring Properties
声明属性的要求

To declare a property, use the Q_PROPERTY() macro in a class that inherits QObject.
要声明属性,请在继承 QObject 的类中使用 Q_PROPERTY() 宏。

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]
           [REQUIRED])

Here are some typical examples of property declarations taken from class QWidget.
以下是一些从 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)

Here is an example showing how to export member variables as Qt properties using the MEMBER keyword. Note that a NOTIFY signal must be specified to allow QML property bindings.
这是一个示例,演示如何使用 MEMBER 关键字将成员变量导出为 Qt 属性。请注意,必须指定 NOTIFY 信号才能允许 QML 属性绑定。

    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;

A property behaves like a class data member, but it has additional features accessible through the Meta-Object System.
属性的行为类似于类数据成员,但它具有可通过元对象系统访问的其他功能。

  • A READ accessor function is required if no MEMBER variable was specified. It is for reading the property value. Ideally, a const function is used for this purpose, and it must return either the property's type or a const reference to that type. e.g., QWidget::focus is a read-only property with READ function, QWidget::hasFocus().
    如果未指定 MEMBER 变量,则需要一个 READ 访问器函数。它用于读取属性值。理想情况下,为此目的使用 const 函数,并且它必须返回属性的类型或对该类型的 const 引用。例如,QWidget::focus 是一个具有 READ 函数的只读属性,QWidget::hasFocus()。
  • A WRITE accessor function is optional. It is for setting the property value. It must return void and must take exactly one argument, either of the property's type or a pointer or reference to that type. e.g., QWidget::enabled has the WRITE function QWidget::setEnabled(). Read-only properties do not need WRITE functions. e.g., QWidget::focus has no WRITE function.
    WRITE 访问器函数是可选的。它用于设置属性值。它必须返回 void,并且必须只接受一个参数,该参数可以是属性的类型,也可以是指向该类型的指针或引用。例如,QWidget::enabled 具有 WRITE 函数 QWidget::setEnabled()。只读属性不需要 WRITE 函数。例如,QWidget::focus 没有 WRITE 函数。
  • A MEMBER variable association is required if no READ accessor function is specified. This makes the given member variable readable and writable without the need of creating READ and WRITE accessor functions. It's still possible to use READ or WRITE accessor functions in addition to MEMBER variable association (but not both), if you need to control the variable access.
    如果未指定 READ 访问器函数,则需要 MEMBER 变量关联。这使得无需创建 READWRITE 访问器函数即可读取和写入给定的成员变量。如果您需要控制变量访问,仍然可以除了 MEMBER 变量关联之外,还可以使用 READWRITE 访问器函数(但不能同时使用两者)。
  • A RESET function is optional. It is for setting the property back to its context specific default value. e.g., QWidget::cursor has the typical READ and WRITE functions, QWidget::cursor() and QWidget::setCursor(), and it also has a RESET function, QWidget::unsetCursor(), since no call to QWidget::setCursor() can mean reset to the context specific cursor. The RESET function must return void and take no parameters.
    RESET 函数是可选的。它用于将属性设置回其上下文相关的默认值。例如,QWidget::cursor 具有典型的 READWRITE 函数,QWidget::cursor()和 QWidget::setCursor(),并且它还有一个 RESET 函数,QWidget::unsetCursor(),因为没有对 QWidget::setCursor()的调用可能意味着重置为上下文相关的游标。 RESET 函数必须返回 void 并且不接受任何参数。
  • A NOTIFY signal is optional. If defined, it should specify one existing signal in that class that is emitted whenever the value of the property changes. NOTIFY signals for MEMBER variables must take zero or one parameter, which must be of the same type as the property. The parameter will take the new value of the property. The NOTIFY signal should only be emitted when the property has really been changed, to avoid bindings being unnecessarily re-evaluated in QML, for example. Qt emits automatically that signal when needed for MEMBER properties that do not have an explicit setter.
    一个 NOTIFY 信号是可选的。如果已定义,它应该指定该类中一个现有的信号,该信号在属性值更改时发出。 NOTIFY 变量的 MEMBER 信号必须接受零个或一个参数,该参数必须与属性类型相同。该参数将采用属性的新值。 NOTIFY 信号仅应在属性确实发生更改时发出,以避免例如在 QML 中不必要地重新评估绑定。对于没有显式设置器的 MEMBER 属性,Qt 会在需要时自动发出该信号。
  • A REVISION number is optional. If included, it defines the property and its notifier signal to be used in a particular revision of the API (usually for exposure to QML). If not included, it defaults to 0.
    一个 REVISION 数字是可选的。如果包含,它定义属性及其通知器信号,以便在 API 的特定版本中使用(通常用于公开给 QML)。如果不包含,则默认为 0。
  • The DESIGNABLE attribute indicates whether the property should be visible in the property editor of GUI design tool (e.g., Qt Designer). Most properties are DESIGNABLE (default true). Instead of true or false, you can specify a boolean member function.
    DESIGNABLE 属性指示该属性是否应该在 GUI 设计工具(例如 Qt Designer)的属性编辑器中可见。大多数属性为 DESIGNABLE (默认值为 true)。您可以指定布尔成员函数,而不是 true 或 false。
  • The SCRIPTABLE attribute indicates whether this property should be accessible by a scripting engine (default true). Instead of true or false, you can specify a boolean member function.
    SCRIPTABLE 属性指示此属性是否应该可被脚本引擎访问(默认为 true)。您可以指定布尔成员函数,而不是 true 或 false。
  • The STORED attribute indicates whether the property should be thought of as existing on its own or as depending on other values. It also indicates whether the property value must be saved when storing the object's state. Most properties are STORED (default true), but e.g., QWidget::minimumWidth() has STORED false, because its value is just taken from the width component of property QWidget::minimumSize(), which is a QSize.
    STORED 属性指示该属性应该被认为是独立存在的,还是依赖于其他值。它还指示在存储对象状态时是否必须保存属性值。大多数属性都是 STORED (默认为 true),但例如,QWidget::minimumWidth() 的 STORED 为 false,因为它的值只是从属性 QWidget::minimumSize()(这是一个 QSize)的宽度组件中获取的。
  • The USER attribute indicates whether the property is designated as the user-facing or user-editable property for the class. Normally, there is only one USER property per class (default false). e.g., QAbstractButton::checked is the user editable property for (checkable) buttons. Note that QItemDelegate gets and sets a widget's USER property.
    USER 属性指示该属性是否被指定为类的面向用户或用户可编辑的属性。通常,每个类只有一个 USER 属性(默认为 false)。例如,QAbstractButton::checked 是(可选中)按钮的用户可编辑属性。请注意,QItemDelegate 获取并设置小部件的 USER 属性。
  • The presence of the CONSTANT attribute indicates that the property value is constant. For a given object instance, the READ method of a constant property must return the same value every time it is called. This constant value may be different for different instances of the object. A constant property cannot have a WRITE method or a NOTIFY signal.
    CONSTANT 属性的存在指示属性值是常量。对于给定的对象实例,常量属性的 READ 方法必须每次调用时都返回相同的值。对于对象的不同的实例,此常量值可能不同。常量属性不能有 WRITE 方法或 NOTIFY 信号。
  • The presence of the FINAL attribute indicates that the property will not be overridden by a derived class. This can be used for performance optimizations in some cases, but is not enforced by moc. Care must be taken never to override a FINAL property.
    FINAL 属性的存在表明该属性不会被派生类覆盖。在某些情况下,这可以用于性能优化,但 moc 并不强制执行。必须注意永远不要覆盖 FINAL 属性。
  • The presence of the REQUIRED attribute indicates that the property should be set by a user of the class. This is not enforced by moc, and is mostly useful for classes exposed to QML. In QML, classes with REQUIRED properties cannot be instantiated unless all REQUIRED properties have been set.
    REQUIRED 属性的存在表明该属性应该由类的用户设置。moc 不强制执行此项,主要用于公开给 QML 的类。在 QML 中,除非所有 REQUIRED 属性都已设置,否则具有 REQUIRED 属性的类无法实例化。

The READ, WRITE, and RESET functions can be inherited. They can also be virtual. When they are inherited in classes where multiple inheritance is used, they must come from the first inherited class.
READWRITERESET 函数可以被继承。它们也可以是虚拟函数。当它们在使用多重继承的类中被继承时,它们必须来自第一个继承的类。

The property type can be any type supported by QVariant, or it can be a user-defined type. In this example, class QDate is considered to be a user-defined type.
属性类型可以是 QVariant 支持的任何类型,也可以是用户定义的类型。在此示例中,类 QDate 被视为用户定义类型。

Q_PROPERTY(QDate date READ getDate WRITE setDate)

Because QDate is user-defined, you must include the <QDate> header file with the property declaration.
由于 QDate 是用户定义的,因此您必须在属性声明中包含 <QDate> 头文件。

For historical reasons, QMap and QList as property types are synonym of QVariantMap and QVariantList.
由于历史原因,QMap 和 QList 作为属性类型是 QVariantMap 和 QVariantList 的同义词。

Reading and Writing Properties with the Meta-Object System
使用元对象系统读取和写入属性

A property can be read and written using the generic functions QObject::property() and QObject::setProperty(), without knowing anything about the owning class except the property's name. In the code snippet below, the call to QAbstractButton::setDown() and the call to QObject::setProperty() both set property "down".
可以使用通用函数 QObject::property() 和 QObject::setProperty() 读取和写入属性,无需了解拥有该属性的类的任何信息,只需知道属性名称即可。在下面的代码片段中,对 QAbstractButton::setDown() 的调用和对 QObject::setProperty() 的调用都设置了 "down" 属性。

QPushButton *button = new QPushButton;
QObject *object = button;

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

Accessing a property through its WRITE accessor is the better of the two, because it is faster and gives better diagnostics at compile time, but setting the property this way requires that you know about the class at compile time. Accessing properties by name lets you access classes you don't know about at compile time. You can discover a class's properties at run time by querying its QObject, QMetaObject, and QMetaProperties.
通过其 WRITE 访问器访问属性更好,因为它更快,并且在编译时提供更好的诊断,但是以这种方式设置属性要求您在编译时了解该类。通过名称访问属性允许您访问在编译时不知道的类。您可以通过查询其 QObject、QMetaObject 和 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);
    ...
}

In the above snippet, QMetaObject::property() is used to get metadata about each property defined in some unknown class. The property name is fetched from the metadata and passed to QObject::property() to get the value of the property in the current object.
在上面的代码片段中,QMetaObject::property() 用于获取在某个未知类中定义的每个属性的元数据。属性名称从元数据中获取,并传递给 QObject::property() 以获取当前对象中属性的值。

A Simple Example  一个简单的示例

Suppose we have a class MyClass, which is derived from QObject and which uses the Q_OBJECT macro in its private section. We want to declare a property in MyClass to keep track of a priority value. The name of the property will be priority, and its type will be an enumeration type named Priority, which is defined in MyClass.
假设我们有一个类 MyClass,它派生自 QObject 并在其私有部分使用 Q_OBJECT 宏。我们想在 MyClass 中声明一个属性来跟踪优先级值。属性名称将是 priority,其类型是一个名为 Priority 的枚举类型,该枚举类型在 MyClass 中定义。

We declare the property with the Q_PROPERTY() macro in the private section of the class. The required READ function is named priority, and we include a WRITE function named setPriority. The enumeration type must be registered with the Meta-Object System using the Q_ENUM() macro. Registering an enumeration type makes the enumerator names available for use in calls to QObject::setProperty(). We must also provide our own declarations for the READ and WRITE functions. The declaration of MyClass then might look like this:
我们在类的私有部分声明属性,使用 Q_PROPERTY() 宏。所需的 READ 函数名为 priority ,我们包含一个名为 setPriorityWRITE 函数。枚举类型必须使用 Q_ENUM() 宏注册到元对象系统。注册枚举类型可使枚举器名称可用于 QObject::setProperty() 的调用。我们还必须提供我们自己的 READWRITE 函数声明。MyClass 的声明可能如下所示:

class MyClass : public QObject
{
    Q_OBJECT
    Q_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;
};

The READ function is const and returns the property type. The WRITE function returns void and has exactly one parameter of the property type. The meta-object compiler enforces these requirements.
READ 函数是 const 函数并返回属性类型。 WRITE 函数返回 void 类型且只有一个属性类型的参数。元对象编译器强制执行这些要求。

Given a pointer to an instance of MyClass or a pointer to a QObject that is an instance of MyClass, we have two ways to set its priority property:
如果给定一个 MyClass 实例的指针或一个 QObject 指针,该指针指向 MyClass 的实例,则有两种方法来设置其优先级属性:

MyClass *myinstance = new MyClass;
QObject *object = myinstance;

myinstance->setPriority(MyClass::VeryHigh);
object->setProperty("priority", "VeryHigh");

In the example, the enumeration type that is the property type is declared in MyClass and registered with the Meta-Object System using the Q_ENUM() macro. This makes the enumeration values available as strings for use as in the call to setProperty(). Had the enumeration type been declared in another class, its fully qualified name (i.e., OtherClass::Priority) would be required, and that other class would also have to inherit QObject and register the enumeration type there using the Q_ENUM() macro.
在示例中,枚举类型(即属性类型)在 MyClass 中声明,并使用 Q_ENUM() 宏注册到元对象系统。这使得枚举值可用作字符串,可用于 setProperty() 的调用。如果枚举类型声明在另一个类中,则需要其完全限定名称(例如,OtherClass::Priority),并且该其他类也必须继承 QObject 并使用 Q_ENUM() 宏在其中注册该枚举类型。

A similar macro, Q_FLAG(), is also available. Like Q_ENUM(), it registers an enumeration type, but it marks the type as being a set of flags, i.e. values that can be OR'd together. An I/O class might have enumeration values Read and Write and then QObject::setProperty() could accept Read | Write. Q_FLAG() should be used to register this enumeration type.
还有一个类似的宏 Q_FLAG()。与 Q_ENUM() 一样,它也注册一个枚举类型,但它将类型标记为一组标志,即可以一起或的数值。一个 I/O 类可能有枚举值 ReadWrite ,然后 QObject::setProperty() 可以接受 Read | Write 。应该使用 Q_FLAG() 来注册此枚举类型。

Dynamic Properties  动态属性

QObject::setProperty() can also be used to add new properties to an instance of a class at runtime. When it is called with a name and a value, if a property with the given name exists in the QObject, and if the given value is compatible with the property's type, the value is stored in the property, and true is returned. If the value is not compatible with the property's type, the property is not changed, and false is returned. But if the property with the given name doesn't exist in the QObject (i.e., if it wasn't declared with Q_PROPERTY()), a new property with the given name and value is automatically added to the QObject, but false is still returned. This means that a return of false can't be used to determine whether a particular property was actually set, unless you know in advance that the property already exists in the QObject.
QObject::setProperty() 也可用于在运行时向类的实例添加新属性。当它使用名称和值调用时,如果 QObject 中存在具有给定名称的属性,并且如果给定值与属性的类型兼容,则该值将存储在属性中,并返回 true。如果该值与属性的类型不兼容,则属性不会更改,并返回 false。但是,如果 QObject 中不存在具有给定名称的属性(即,如果它没有用 Q_PROPERTY()声明),则会自动向 QObject 添加一个具有给定名称和值的新属性,但仍然返回 false。这意味着除非您预先知道该属性已存在于 QObject 中,否则无法使用 false 返回值来确定是否实际设置了特定属性。

Note that dynamic properties are added on a per instance basis, i.e., they are added to QObject, not QMetaObject. A property can be removed from an instance by passing the property name and an invalid QVariant value to QObject::setProperty(). The default constructor for QVariant constructs an invalid QVariant.
请注意,动态属性是基于每个实例添加的,即,它们添加到 QObject,而不是 QMetaObject。可以通过将属性名称和无效的 QVariant 值传递给 QObject::setProperty()来从实例中删除属性。QVariant 的默认构造函数构造一个无效的 QVariant。

Dynamic properties can be queried with QObject::property(), just like properties declared at compile time with Q_PROPERTY().
可以使用 QObject::property()查询动态属性,就像使用 Q_PROPERTY()在编译时声明的属性一样。

Properties and Custom Types
属性和自定义类型

Custom types used by properties need to be registered using the Q_DECLARE_METATYPE() macro so that their values can be stored in QVariant objects. This makes them suitable for use with both static properties declared using the Q_PROPERTY() macro in class definitions and dynamic properties created at run-time.
属性使用的自定义类型需要使用 Q_DECLARE_METATYPE() 宏进行注册,以便其值可以存储在 QVariant 对象中。这使得它们适用于使用 Q_PROPERTY() 宏在类定义中声明的静态属性以及在运行时创建的动态属性。

Adding Additional Information to a Class
向类添加附加信息

Connected to the property system is an additional macro, Q_CLASSINFO(), that can be used to attach additional name--value pairs to a class's meta-object, for example:
连接到属性系统的是一个附加宏 Q_CLASSINFO(),它可以用于将额外的名称-值对附加到类的元对象,例如:

Q_CLASSINFO("Version", "3.0.0")

Like other meta-data, class information is accessible at run-time through the meta-object; see QMetaObject::classInfo() for details.

See also Meta-Object System, Signals and Slots, Q_DECLARE_METATYPE(), QMetaType, and QVariant.

© 2024 The Qt Company Ltd. Documentation contributions included herein are the copyrights of their respective owners. The documentation provided herein is licensed under the terms of the GNU Free Documentation License version 1.3 as published by the Free Software Foundation. Qt and respective logos are trademarks of The Qt Company Ltd. in Finland and/or other countries worldwide. All other trademarks are property of their respective owners.