El sistema de propiedades
Qt proporciona un sofisticado sistema de propiedades similar a los proporcionados por algunos proveedores de compiladores. Sin embargo, como librería independiente del compilador y de la plataforma, Qt no depende de características de compiladores no estándar como __property o [property]. La solución Qt funciona con cualquier compilador C++ estándar en todas las plataformas que soporta Qt. Se basa en el sistema Meta-Object, que también proporciona comunicación entre objetos a través de señales y ranuras.
Requisitos para declarar propiedades
Para declarar una propiedad, utilice la macro Q_PROPERTY() en una clase que herede QObject.
Q_PROPERTY(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int | REVISION(int[, int])]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[BINDABLE bindableProperty]
[CONSTANT]
[FINAL]
[VIRTUAL]
[OVERRIDE]
[REQUIRED])A continuación se muestran algunos ejemplos típicos de declaración de propiedades tomados de la clase 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)
He aquí un ejemplo que muestra cómo exportar variables miembro como propiedades Qt utilizando la palabra clave MEMBER. Observe que debe especificarse una señal NOTIFY para permitir los enlaces de propiedades 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;
Una propiedad se comporta como un miembro de datos de una clase, pero tiene características adicionales accesibles a través del Sistema de Meta-Objetos.
- Se requiere una función de acceso
READsi no se ha especificado ninguna variableMEMBER. Sirve para leer el valor de la propiedad. Lo ideal es utilizar una función const para este propósito, y debe devolver el tipo de la propiedad o una referencia const a ese tipo. Por ejemplo, QWidget::focus es una propiedad de sólo lectura con la funciónREAD, QWidget::hasFocus(). Si se especificaBINDABLE, puede escribirREAD defaultpara que se genere el accesorREADa partir deBINDABLE. - La función de acceso
WRITEes opcional. Sirve para establecer el valor de la propiedad. Debe devolver void y debe tomar exactamente un argumento, ya sea del tipo de la propiedad o un puntero o referencia a ese tipo. Por ejemplo, QWidget::enabled tiene la funciónWRITEQWidget::setEnabled (). Las propiedades de sólo lectura no necesitan las funcionesWRITE. Por ejemplo, QWidget::focus no tiene la funciónWRITE. Si especifica tanto unBINDABLEcomo unWRITE default, se generará un accesorWRITEa partir delBINDABLE. El accesorWRITEgenerado no emitirá explícitamente ninguna señal declarada conNOTIFY. Deberá registrar la señal como gestor de cambios en elBINDABLE, por ejemplo utilizando Q_OBJECT_BINDABLE_PROPERTY. - Se requiere una asociación de variable
MEMBERsi no se especifica una función de accesorREAD. Esto hace que la variable miembro dada sea legible y escribible sin necesidad de crear funciones accesoriasREADyWRITE. Aún es posible utilizar funciones accesoriasREADoWRITEademás de la asociación de variablesMEMBER(pero no ambas), si necesita controlar el acceso a la variable. - La función
RESETes opcional. Sirve para devolver la propiedad a su valor por defecto específico del contexto. Por ejemplo, QWidget::cursor tiene las funciones típicasREADyWRITE, QWidget::cursor() y QWidget::setCursor(), y también tiene una funciónRESET, QWidget::unsetCursor(), ya que ninguna llamada a QWidget::setCursor() puede significar el restablecimiento al cursor específico del contexto. La funciónRESETdebe devolver void y no tomar parámetros. - Una señal
NOTIFYes opcional. Si se define, debe especificar una señal existente en esa clase que se emita cada vez que cambie el valor de la propiedad. Las señalesNOTIFYpara variablesMEMBERdeben tomar cero o un parámetro, que debe ser del mismo tipo que la propiedad. El parámetro tomará el nuevo valor de la propiedad. La señalNOTIFYsólo debe emitirse cuando la propiedad ha cambiado realmente, para evitar que los enlaces se reevalúen innecesariamente en QML, por ejemplo. La señal se emite automáticamente cuando la propiedad se cambia a través de la API de Qt (QObject::setProperty, QMetaProperty, etc.), pero no cuando el MEMBER se cambia directamente. - El número
REVISIONo la macroREVISION()son opcionales. Si se incluye, define la propiedad y su señal notificadora que se utilizará en una revisión concreta de la API (normalmente para la exposición a QML). Si no se incluye, su valor predeterminado es 0. - El atributo
DESIGNABLEindica si la propiedad debe ser visible en el editor de propiedades de la herramienta de diseño GUI (por ejemplo, Qt Widgets Designer). La mayoría de las propiedades sonDESIGNABLE(por defecto true). Los valores válidos son true y false. - El atributo
SCRIPTABLEindica si esta propiedad debe ser accesible por un motor de scripting (por defecto true). Los valores válidos son true y false. - El atributo
STOREDindica si la propiedad debe considerarse como existente por sí misma o como dependiente de otros valores. También indica si el valor de la propiedad debe guardarse al almacenar el estado del objeto. La mayoría de las propiedades sonSTORED(por defecto true), pero por ejemplo, QWidget::minimumWidth() tieneSTOREDfalse, porque su valor sólo se toma del componente width de la propiedad QWidget::minimumSize(), que es un QSize. - El atributo
USERindica si la propiedad está designada como propiedad de cara al usuario o propiedad editable por el usuario para la clase. Normalmente, sólo hay una propiedadUSERpor clase (por defecto, false). Por ejemplo, QAbstractButton::checked es la propiedad editable por el usuario para los botones (comprobables). Tenga en cuenta que QItemDelegate obtiene y establece la propiedadUSERde un widget. - El atributo
BINDABLE bindablePropertyindica que la propiedad soporta bindings, y que es posible establecer e inspeccionar bindings a esta propiedad a través del meta object system (QMetaProperty).bindablePropertynombra un miembro de la clase de tipo QBindable<T>, donde T es el tipo de propiedad. Este atributo se introdujo en Qt 6.0. - La presencia del atributo
CONSTANTindica que el valor de la propiedad es constante. Para una instancia de objeto dada, el método READ de una propiedad constante debe devolver el mismo valor cada vez que es llamado. Este valor constante puede ser diferente para distintas instancias del objeto. Una propiedad constante no puede tener un método WRITE ni una señal NOTIFY. FINALLos modificadoresVIRTUAL,OVERRIDEreflejan la semántica de sus equivalentes en C++ y QML, permitiendo hacer explícita la sobreescritura de propiedades a nivel de metaobjeto.Nota: En la actualidad, moc no aplica estos modificadores. Se reconocen sintácticamente y se utilizan principalmente para la aplicación en tiempo de ejecución de QML y el diagnóstico de herramientas. Es posible que las versiones futuras introduzcan una validación más estricta en tiempo de compilación y advertencias en caso de anulaciones no válidas entre módulos.
Nota: Si desea cambiar el comportamiento de acceso a una propiedad, utilice el polimorfismo proporcionado por C++.
- La presencia del atributo
REQUIREDindica que la propiedad debe ser establecida por un usuario de la clase. Esto no lo impone moc, y es útil sobre todo para las clases expuestas a QML. En QML, las clases con propiedades REQUIRED no pueden instanciarse a menos que se hayan establecido todas las propiedades REQUIRED.
Las funciones READ, WRITE, y RESET pueden heredarse. También pueden ser virtuales. Cuando se heredan en clases en las que se utiliza herencia múltiple, deben proceder de la primera clase heredada.
El tipo de propiedad puede ser cualquier tipo soportado por QVariant, o puede ser un tipo definido por el usuario. En este ejemplo, la clase QDate se considera un tipo definido por el usuario.
Q_PROPERTY(QDate date READ getDate WRITE setDate)Dado que QDate está definido por el usuario, debe incluir el archivo de cabecera <QDate> con la declaración de propiedades.
Por razones históricas, QMap y QList como tipos de propiedad son sinónimos de QVariantMap y QVariantList.
Lectura y escritura de propiedades con el sistema de metaobjetos
Una propiedad puede leerse y escribirse utilizando las funciones genéricas QObject::property() y QObject::setProperty(), sin saber nada de la clase propietaria excepto el nombre de la propiedad. En el siguiente fragmento de código, tanto la llamada a QAbstractButton::setDown() como la llamada a QObject::setProperty() establecen la propiedad "down".
QPushButton *button = new QPushButton; QObject *object = button; button->setDown(true); object->setProperty("down", true);
Acceder a una propiedad a través de su accesorio WRITE es la mejor de las dos, porque es más rápido y da mejores diagnósticos en tiempo de compilación, pero establecer la propiedad de esta manera requiere que conozcas la clase en tiempo de compilación. Acceder a las propiedades por nombre te permite acceder a clases que no conoces en tiempo de compilación. Puedes descubrir las propiedades de una clase en tiempo de ejecución consultando sus QObject, QMetaObject, y QMetaProperties.
QObject *object = new QObject; 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); //... }
En el fragmento anterior, QMetaObject::property() se utiliza para obtener metadata sobre cada propiedad definida en una clase desconocida. El nombre de la propiedad se obtiene de los metadatos y se pasa a QObject::property() para obtener el value de la propiedad en el object actual.
Un ejemplo sencillo
Supongamos que tenemos una clase MyClass, que deriva de QObject y que utiliza la macro Q_OBJECT. Queremos declarar una propiedad en MyClass para llevar la cuenta de un valor de prioridad. El nombre de la propiedad será priority, y su tipo será un tipo de enumeración llamado Priority, que está definido en MyClass.
Declaramos la propiedad con la macro Q_PROPERTY() en la sección private de la clase. La función requerida READ se llama priority, e incluimos una función WRITE llamada setPriority. El tipo de enumeración debe registrarse en el Sistema de Meta-Objetos mediante la macro Q_ENUM(). El registro de un tipo de enumeración hace que los nombres de los enumeradores estén disponibles para su uso en las llamadas a QObject::setProperty(). También debemos proporcionar nuestras propias declaraciones para las funciones READ y WRITE. La declaración de MyClass podría tener este aspecto:
class MyClass : public QObject { Q_OBJECT Q_PROPERTY(Priority priority READ priority WRITE setPriority NOTIFY priorityChanged) public: MyClass(QObject *parent = nullptr); ~MyClass(); enum Priority { High, Low, VeryHigh, VeryLow }; Q_ENUM(Priority) void setPriority(Priority priority) { if (m_priority == priority) return; m_priority = priority; emit priorityChanged(priority); } Priority priority() const { return m_priority; } signals: void priorityChanged(Priority); private: Priority m_priority; };
La función READ es const y devuelve el tipo de propiedad. La función WRITE devuelve void y tiene exactamente un parámetro del tipo de propiedad. El compilador de meta-objetos hace cumplir estos requisitos. La comprobación de igualdad en la función WRITE, aunque no es obligatoria, es una buena práctica, ya que no tiene sentido notificar y forzar potencialmente la reevaluación en otros lugares si nada ha cambiado.
Dado un puntero a una instancia de MyClass o un puntero a un QObject que es una instancia de MyClass, tenemos dos formas de establecer su propiedad de prioridad:
MyClass *myinstance = new MyClass; QObject *object = myinstance; myinstance->setPriority(MyClass::VeryHigh); object->setProperty("priority", "VeryHigh");
En el ejemplo, el tipo de enumeración que es el tipo de propiedad se declara en MyClass y se registra en el Sistema de Meta-Objetos utilizando la macro Q_ENUM(). Esto hace que los valores de enumeración estén disponibles como cadenas para su uso como en la llamada a setProperty(). Si el tipo de enumeración se hubiera declarado en otra clase, se necesitaría su nombre completo (es decir, OtraClase::Prioridad), y esa otra clase también tendría que heredar QObject y registrar el tipo de enumeración allí utilizando la macro Q_ENUM().
También existe una macro similar, Q_FLAG(). Al igual que Q_ENUM(), registra un tipo de enumeración, pero marca el tipo como un conjunto de flags, es decir, valores que pueden ser OR'd juntos. Una clase de E/S podría tener los valores de enumeración Read y Write y entonces QObject::setProperty() podría aceptar Read | Write. Q_FLAG() debería usarse para registrar este tipo de enumeración.
Propiedades dinámicas
QObject::setProperty() también puede utilizarse para añadir nuevas propiedades a una instancia de una clase en tiempo de ejecución. Cuando se llama con un nombre y un valor, si existe una propiedad con el nombre dado en QObject, y si el valor dado es compatible con el tipo de la propiedad, el valor se almacena en la propiedad, y se devuelve true. Si el valor no es compatible con el tipo de la propiedad, la propiedad no se modifica y se devuelve false. Pero si la propiedad con el nombre dado no existe en QObject (es decir, si no se declaró con Q_PROPERTY()), se añade automáticamente una nueva propiedad con el nombre y valor dados a QObject, pero se sigue devolviendo false. Esto significa que un resultado falso no puede utilizarse para determinar si una propiedad concreta se ha establecido realmente, a menos que se sepa de antemano que la propiedad ya existe en QObject.
Tenga en cuenta que las propiedades dinámicas se añaden por instancia, es decir, se añaden a QObject, no a QMetaObject. Una propiedad puede ser eliminada de una instancia pasando el nombre de la propiedad y un valor QVariant inválido a QObject::setProperty(). El constructor por defecto de QVariant construye un QVariant no válido.
Las propiedades dinámicas pueden consultarse con QObject::property(), al igual que las propiedades declaradas en tiempo de compilación con Q_PROPERTY().
Propiedades y tipos personalizados
Los tipos personalizados utilizados por las propiedades deben registrarse mediante la macro Q_DECLARE_METATYPE() para que sus valores puedan almacenarse en objetos QVariant. Esto los hace adecuados para su uso tanto con propiedades estáticas declaradas utilizando la macro Q_PROPERTY() en las definiciones de clase como con propiedades dinámicas creadas en tiempo de ejecución.
Añadir información adicional a una clase
Conectada al sistema de propiedades existe una macro adicional, Q_CLASSINFO(), que puede utilizarse para adjuntar pares nombre-valor adicionales al metaobjeto de una clase. Esto se utiliza, por ejemplo, para marcar una propiedad como predeterminada en el contexto de los tipos de objeto QML:
Q_CLASSINFO("DefaultProperty", "content")
Al igual que otros metadatos, la información de la clase es accesible en tiempo de ejecución a través del metaobjeto; véase QMetaObject::classInfo() para más detalles.
Uso de propiedades vinculables
Se pueden utilizar tres tipos diferentes para implementar propiedades enlazables:
La primera es una clase general para propiedades vinculables. Las dos últimas sólo pueden utilizarse dentro de QObject.
Para obtener más información, incluidos ejemplos, consulte las clases mencionadas anteriormente y los consejos generales sobre la implementación y el uso de propiedades vinculables.
Véase también Meta-Object System, Signals and Slots, Q_DECLARE_METATYPE(), QMetaType, QVariant, Qt Bindable Properties, y Defining QML Types from C++.
© 2026 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.