CopperSpice API  1.9.1
Property System

A property provides meta data about data stored in an object. CopperSpice contains full support for both compile time and run time properties. The implementation does not rely on or use compiler attributes, it is based on the Meta Object System.

Requirements for Declaring Properties

To declare a property use the CS_PROPERTY macros in a class which inherits from QObject.

CS_PROPERTY_READ(name, getFunction)
CS_PROPERTY_WRITE(name, setFunction)
CS_PROPERTY_RESET(name, resetFunction)
CS_PROPERTY_NOTIFY(name, notifySignal)
CS_PROPERTY_REVISION(name, <integer value>)
CS_PROPERTY_DESIGNABLE(name, true / false)
CS_PROPERTY_SCRIPTABLE(name, true / false)
CS_PROPERTY_STORED(name, true / false)
CS_PROPERTY_USER(name, true / false)
CS_PROPERTY_CONSTANT(name)
CS_PROPERTY_FINAL(name)

The following are four property declarations taken from the QWidget class in CopperSpice.

CS_PROPERTY_READ(focus, hasFocus)
CS_PROPERTY_READ(enabled, isEnabled)
CS_PROPERTY_WRITE(enabled, setEnabled)
CS_PROPERTY_READ(minimumWidth, minimumWidth)
CS_PROPERTY_WRITE(minimumWidth, setMinimumWidth)
CS_PROPERTY_STORED(minimumWidth, false)
CS_PROPERTY_DESIGNABLE(minimumWidth, false)
CS_PROPERTY_READ(cursor, cursor)
CS_PROPERTY_WRITE(cursor, setCursor)
CS_PROPERTY_RESET(cursor, unsetCursor)

A property is similar to a class data member with additional features which are accessible through the Meta Object System. The property type can be any copyable data type.

READ The read method is required. The read method must be const, take no arguments and return the property's type. For example QWidget::focus is a read-only property with read method QWidget::hasFocus().
WRITE The write method is used for setting the property value. If no write method is specified the property is read only. It must return void and must take exactly one argument. For example, QWidget::enabled has the write method QWidget::setEnabled(bool).
RESET The reset method is optional. It is used to set the property back to its default value. The reset method must return void and take no parameters.
NOTIFY The signal is optional. If defined notify specifies one existing signal in that class that is emitted whenever the value of the property changes.
REVISION The number is optional. If included revision defines the property to be used in a particular revision of the API that is exposed to QML.
DESIGNABLE The designable attribute indicates whether the property should be visible in the property editor of GUI design tool. Most properties are designable. Instead of true or false, you can specify a boolean method or expression.
SCRIPTABLE The scriptable attribute indicates whether this property should be accessible by a scripting engine. The default is true. Instead of true or false, you can specify a boolean method or expression.
STORED The stored attribute indicates whether the property should exists on its own or is computed from other values. It also indicates whether the property value must be saved when storing the object's state. Most properties are stored. The default is true. For example, QWidget::minimumWidth() has stored set to false because its value is taken from the width component of property QWidget::minimumSize(), which is a QSize.
USER The user attribute indicates which property in a given widget contains the value of the widget. There is only one user property per class and the default is false. For example, QAbstractButton::checked is the user property for checkable buttons and indicates the value of the button.
CONSTANT 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 can not have a write method or a notify signal.
FINAL 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. Do not override a final property.

Reading and Writing Properties

A property can be queried and set using the QObject::property() and QObject::setProperty() without knowing anything about the target class. You must know the name of the property and a data type which is compatible with the data type of the property. In the code shown below, the call to QAbstractButton::setText() and the call to QObject::setProperty() accomplish the same result.

QPushButton *button = new QPushButton;
button->setText("Close"); // calls a method of QPushButton
QObject *obj = button;
obj->setProperty("text", "Close"); // uses the property system

Calling setText() has some advantages since it is faster and may provide better diagnostics at compile time. Using setProperty() may be more flexible since the name of the property is the only component which is required.

The following code shows how to look up all the properties for QPushButton at run time. QMetaObject::property() is used to get metadata about each property defined in some class. The property name is retrieved from the metadata and passed to QObject::property() to load the value of the property in the current object.

QObject *obj = new QPushButton;
const QMetaObject *metaobject = object->metaObject();
int count = metaobject->propertyCount();
for (int i = 0; i<count; ++i) {
QMetaProperty metaproperty = metaobject->property(i);
const QString name = metaproperty.name();
QVariant value = object->property(name);
// do something with value
}

Example

In the following example MyClass inherits from QObject and uses the CS_OBJECT macro. 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 data type will be an enumeration named Priority.

The code declares the property with the CS_PROPERTY macros in the private section of the class. The READ method is named priority and the WRITE method is named setPriority. The READ method is const qualified and returns the value of the property. The WRITE method returns nothing and has exactly one parameter. The CopperSpice meta object system enforces these requirements.

The enumeration type must be registered with the Meta Object System using the CS_ENUM() macro. Registering an enumeration type makes the enumerator values available for use in calls to QObject::setProperty().

class MyClass : public QObject
{
CS_OBJECT(MyClass)
CS_PROPERTY_READ(priority, priority)
CS_PROPERTY_WRITE(priority, setPriority)
CS_PROPERTY_NOTIFY(priority, priorityChanged)
CS_ENUM(Priority)
public:
MyClass(QObject *parent = nullptr);
~MyClass();
enum Priority { High, Low, VeryHigh, VeryLow };
void setPriority(Priority priority) {
if (m_priority == priority) {
return;
}
m_priority = priority;
emit priorityChanged(priority);
}
Priority priority() const {
return m_priority;
}
CS_SIGNAL_1(Public, void priorityChanged(Priority data))
CS_SIGNAL_2(priorityChanged, data)
private:
Priority m_priority;
};

Given the preceding class declaration, the following code declares a pointer to an instance of MyClass. As in the push button example shown above, there are two ways to set the property.

MyClass *task = new MyClass;
task->setPriority(MyClass::VeryHigh); // calls a method in MyClass
QObject *obj = someObj;
obj->setProperty("priority", "VeryHigh"); // uses the property system

Dynamic Properties

QObject::setProperty() can also be used to add new properties to an instance of a class at runtime. If a property with the passed name exists in the QObject and the passed value is compatible with the property's data type, the value is stored. If no property of that name exists a new dynamic property with the given name and value is automatically added to the QObject.

Dynamic properties belong to a specific instance of a class. A dynamic property can be removed from an instance by passing the property name and an invalid QVariant value to QObject::setProperty().

Dynamic properties can be queried with QObject::property() just like properties declared at compile time with using the CS_PROPERTY macros.

Properties and Custom Types

Custom types used by properties need to be registered using the CS_DECLARE_METATYPE() macro so their values can be stored in QVariant objects. This makes them suitable for use with both static properties declared using the CS_PROPERTY macros in class definitions and dynamic properties created at runtime.

Adding Additional Information to a Class

Connected to the property system is an additional macro called CS_CLASSINFO(). This macro can be used to attach additional name / value pairs to a class meta object. Like other meta data class information is accessible at runtime through the meta object. Refer to the QMetaObject::classInfo() for more information.

CS_CLASSINFO("Version", "1.8.2")
See also
QVariant, CS_DECLARE_METATYPE(), Meta Object System, Signals and Slots