En esta página

Conversión de tipos de datos entre QML y C++

Cuando se intercambian valores de datos entre QML y C++, el motor QML los convierte para que tengan los tipos de datos correctos según corresponda para su uso en QML o C++. Esto requiere que los datos intercambiados sean de un tipo reconocible por el motor.

El motor QML proporciona soporte integrado para un gran número de tipos de datos C++ de Qt. Además, los tipos C++ personalizados pueden registrarse en el sistema de tipos QML para que estén disponibles para el motor.

Para obtener más información sobre C++ y los distintos métodos de integración de QML, consulte la página de descripción general de la integración de C++ y QML.

En esta página se describen los tipos de datos que admite el motor QML y cómo se convierten entre QML y C++.

Propiedad de los datos

Cuando se transfieren datos de C++ a QML, la propiedad de los datos siempre es de C++. La excepción a esta regla es cuando se devuelve un QObject desde una llamada explícita a un método de C++: en este caso, el motor QML asume la propiedad del objeto, a menos que se haya establecido explícitamente que la propiedad del objeto permanezca en C++ invocando QQmlEngine::setObjectOwnership() con QQmlEngine::CppOwnership especificado.

Además, el motor QML respeta la semántica normal de propiedad padre QObject de los objetos Qt C++, y nunca eliminará una instancia QObject que tenga un padre.

Tipos de datos básicos de Qt

Por defecto, QML reconoce los siguientes tipos de datos Qt, que se convierten automáticamente en el tipo de valor QML correspondiente cuando se pasan de C++ a QML y viceversa:

Nota: Las clases proporcionadas por el módulo Qt GUI como QColor, QFont, QQuaternion y QMatrix4x4, sólo están disponibles en QML cuando se incluye el módulo Qt Quick está incluido.

Por comodidad, muchos de estos tipos pueden especificarse en QML mediante valores de cadena, o mediante un método relacionado proporcionado por el objeto QtQml::Qt. Por ejemplo, la propiedad Image::sourceSize es del tipo size (que se traduce automáticamente al tipo QSize ) y puede especificarse mediante un valor de cadena formateado como "anchuraxaltura", o mediante la función Qt.size():

Item {
    Image { sourceSize: "100x200" }
    Image { sourceSize: Qt.size(100, 200) }
}

Consulte la documentación de cada tipo individual en Tipos de valor QML para obtener más información.

Tipos derivados de QObject

Cualquier clase derivada de QObject puede utilizarse como tipo para el intercambio de datos entre QML y C++, siempre que la clase se haya registrado en el sistema de tipos de QML.

El motor permite registrar tanto tipos instanciables como no instanciables. Una vez registrada una clase como tipo QML, puede utilizarse como tipo de datos para el intercambio de datos entre QML y C++. Consulte Registro de tipos C++ con el sistema de tipos QML para obtener más detalles sobre el registro de tipos.

Conversión entre tipos Qt y JavaScript

El motor QML dispone de soporte integrado para convertir una serie de tipos Qt en tipos JavaScript relacionados, y viceversa, al transferir datos entre QML y C++. Esto permite utilizar estos tipos y recibirlos en C++ o JavaScript sin necesidad de implementar tipos personalizados que proporcionen acceso a los valores de los datos y sus atributos.

(Tenga en cuenta que el entorno JavaScript de QML modifica los prototipos de objetos nativos de JavaScript, incluidos los de String, Date y Number, para proporcionar funciones adicionales. Para obtener más información, consulte Entorno de host JavaScript).

De QVariantList y QVariantMap a objetos y arrays de JavaScript

El motor QML proporciona una conversión automática de tipos entre QVariantList y las matrices similares de JavaScript, y entre QVariantMap y los objetos de JavaScript.

Un array-like, en términos de ECMAScript, es un objeto que se utiliza como un array. Los array-likes producidos por la conversión desde QVariantList (y otros contenedores secuenciales de C++) no sólo son eso, sino que también ofrecen los métodos de array comunes y sincronizan automáticamente la propiedad length. Pueden usarse como los Arrays de JavaScript para cualquier propósito práctico. Sin embargo, el método Array.isArray() sigue devolviendo false para ellos.

Por ejemplo, la función definida en QML a continuación espera dos argumentos, una matriz y un objeto, e imprime su contenido utilizando la sintaxis JavaScript estándar para el acceso a elementos de matriz y objeto. El código C++ siguiente llama a esta función, pasándole un QVariantList y un QVariantMap, que se convierten automáticamente en valores de tipo matriz y objeto de JavaScript, respectivamente:

QML
// MyItem.qml
Item {
    function readValues(anArray, anObject) {
        for (var i=0; i<anArray.length; i++)
            console.log("Array item:", anArray[i])

        for (var prop in anObject) {
            console.log("Object item:", prop, "=", anObject[prop])
        }
    }
}
C++
// C++
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QVariantList list;
list << 10 << QColor(Qt::green) << "bottles";

QVariantMap map;
map.insert("language", "QML");
map.insert("released", QDate(2010, 9, 21));

QMetaObject::invokeMethod(view.rootObject(), "readValues",
        Q_ARG(QVariant, QVariant::fromValue(list)),
        Q_ARG(QVariant, QVariant::fromValue(map)));

Esto produce una salida como:

Array item: 10
Array item: #00ff00
Array item: bottles
Object item: language = QML
Object item: released = Tue Sep 21 2010 00:00:00 GMT+1000 (EST)

Del mismo modo, si un tipo C++ utiliza un tipo QVariantList o QVariantMap para un tipo de propiedad o parámetro de método, el valor se puede crear como una matriz u objeto JavaScript en QML, y se convierte automáticamente en un QVariantList o QVariantMap cuando se pasa a C++.

Desde Qt 6.5, las propiedades QVariantList de los tipos C++ pueden modificarse in situ mediante código QML. Desde Qt 6.9, el código QML puede modificar las propiedades QVariantMap de los tipos C++.

QDateTime a Fecha JavaScript

El motor QML proporciona conversión automática de tipos entre valores QDateTime y objetos JavaScript Date.

Por ejemplo, la función definida en QML a continuación espera un objeto JavaScript Date, y también devuelve un nuevo objeto Date con la fecha y hora actuales. El código C++ siguiente llama a esta función, pasándole un valor QDateTime que el motor convierte automáticamente en un objeto Date al pasarlo a la función readDate(). A su vez, la función readDate() devuelve un objeto Date que se convierte automáticamente en un valor QDateTime cuando se recibe en C++:

QML
// MyItem.qml
Item {
    function readDate(dt) {
        console.log("The given date is:", dt.toUTCString());
        return new Date();
    }
}
C++
// C++QQuickView vista(QUrl::fromLocalFile("MiItem.qml"));QDateTime dateTime = QDateTime::currentDateTime();QDateTime retValue;QMetaObject::invokeMethod(view.rootObject(), "readDate",Q_RETURN_ARG(QVariant, retValue),Q_ARG(QVariant, QVariant::fromValue(dateTime));
qDebug() << "Value returned from readDate():" << retValue;

Del mismo modo, si un tipo C++ utiliza un QDateTime para un tipo de propiedad o parámetro de método, el valor puede crearse como un objeto JavaScript Date en QML, y se convierte automáticamente en un valor QDateTime cuando se pasa a C++.

Nota: tenga en cuenta la diferencia en la numeración de los meses: JavaScript numera enero del 0 al 11 para diciembre, con una diferencia de uno respecto a la numeración de Qt de enero del 1 al 12 para diciembre.

Nota: Al utilizar una cadena en JavaScript como valor de un objeto Date, tenga en cuenta que una cadena sin campos de hora (por tanto, una simple fecha) se interpreta como el inicio UTC del día correspondiente, a diferencia de new Date(y, m, d), que utiliza el inicio de la hora local del día. La mayoría de las demás formas de construir un objeto Date en JavaScript producen una hora local, a menos que se utilicen métodos con UTC en sus nombres. Si su programa se ejecuta en una zona detrás de UTC (nominalmente al oeste del Primer Meridiano), el uso de una cadena de sólo fecha dará lugar a un objeto Date cuyo getDate() es uno menos que el número de día de su cadena; normalmente tendrá un valor grande para getHours(). Las variantes UTC de estos métodos, getUTCDate() y getUTCHours(), darán los resultados esperados para este tipo de objetos Date. Véase también la sección siguiente.

QDate y JavaScript Date

El motor QML convierte automáticamente entre QDate y el tipo JavaScript Date representando la fecha por el inicio UTC de su día. Una fecha se vuelve a mapear a QDate a través de QDateTime, seleccionando su método date(), utilizando la forma de hora local de la fecha a menos que la forma UTC de la misma coincida con el inicio del día siguiente, en cuyo caso se utiliza la forma UTC.

Esta disposición ligeramente excéntrica es una solución para el hecho de que la construcción de JavaScript de un objeto Date a partir de una cadena de sólo fecha utiliza el inicio UTC del día, pero new Date(y, m, d) utiliza el inicio en hora local de la fecha indicada, como se discutió en una nota al final de la sección anterior.

Como resultado, cuando una propiedad o parámetro QDate se expone a QML, debe tenerse cuidado al leer su valor: es más probable que los métodos Date.getUTCFullYear(), Date.getUTCMonth() y Date.getUTCDate() ofrezcan los resultados que esperan los usuarios que los métodos correspondientes sin UTC en sus nombres.

Por lo tanto, suele ser más robusto utilizar una propiedad QDateTime. Esto permite controlar, en QDateTime, si la fecha (y la hora) se especifican en términos de UTC o de hora local; siempre que el código JavaScript esté escrito para trabajar con el mismo estándar, debería ser posible evitar problemas.

QTime y JavaScript Date

El motor QML proporciona conversión automática de tipo de valores QTime a objetos JavaScript Date. Como los valores QTime no contienen un componente de fecha, se crea uno sólo para la conversión. Por lo tanto, no debe confiar en el componente de fecha del objeto Date resultante.

Bajo el capó, la conversión de un objeto JavaScript Date a QTime se realiza convirtiendo a un objeto QDateTime (utilizando la hora local) y llamando a su método time().

Tipo de secuencia a matriz JavaScript

Consulte Tipos de secuencia QML para obtener una descripción general de los tipos de secuencia. QtQml module contiene algunos tipos de secuencia que puede utilizar.

También puede crear una estructura de datos tipo lista construyendo una QJSValue utilizando QJSEngine::newArray(). Una matriz JavaScript de este tipo no necesita ninguna conversión al pasarla entre QML y C++. Consulte QJSValue#Working With Arrays para obtener más información sobre cómo manipular matrices JavaScript desde C++.

De QByteArray a ArrayBuffer de JavaScript

El motor QML proporciona conversión automática de tipos entre valores QByteArray y objetos JavaScript ArrayBuffer.

Tipos de valores

Algunos tipos de valor en Qt como QPoint se representan en JavaScript como objetos que tienen las mismas propiedades y funciones que en la API de C++. La misma representación es posible con los tipos de valor personalizados de C++. Para habilitar un tipo de valor personalizado con el motor QML, la declaración de la clase necesita ser anotada con Q_GADGET. Las propiedades que vayan a ser visibles en la representación JavaScript deben declararse con Q_PROPERTY. Del mismo modo, las funciones deben marcarse con Q_INVOKABLE. Lo mismo ocurre con las API de C++ basadas en QObject. Por ejemplo, la siguiente clase Actor está anotada como gadget y tiene propiedades:

class Actor
{
    Q_GADGET
    Q_PROPERTY(QString name READ name WRITE setName)
public:
    QString name() const { return m_name; }
    void setName(const QString &name) { m_name = name; }

private:
    QString m_name;
};

Q_DECLARE_METATYPE(Actor)

El patrón habitual es utilizar una clase gadget como tipo de una propiedad, o emitir un gadget como argumento de una señal. En estos casos, la instancia del gadget se pasa por valor entre C++ y QML (porque es un tipo de valor). Si el código QML cambia una propiedad de un gadget, se vuelve a crear el gadget completo y se pasa de nuevo al definidor de propiedades de C++. En Qt 5, los tipos de gadget no pueden instanciarse mediante declaración directa en QML. En cambio, se puede declarar una instancia de QObject; y las instancias de QObject siempre se pasan por puntero de C++ a QML.

Tipos de enumeración

Para utilizar una enumeración personalizada como tipo de datos, debe registrarse su clase y la enumeración también debe declararse con Q_ENUM() para registrarla en el meta sistema de objetos de Qt. Por ejemplo, la clase Message a continuación tiene una enumeración Status:

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(Status status READ status NOTIFY statusChanged)
public:
    enum Status {
        Ready,
        Loading,
        Error
    };
    Q_ENUM(Status)
    Status status() const;
signals:
    void statusChanged();
};

Siempre que la clase Message haya sido registrada en el sistema de tipos de QML, su enumeración Status puede ser utilizada desde QML:

Message {
     onStatusChanged: {
         if (status == Message.Ready)
             console.log("Message is loaded!")
     }
 }

Para utilizar un enum como tipo flags en QML, consulte Q_FLAG().

Nota: Los nombres de los valores de enum deben empezar con mayúscula para ser accesibles desde QML.

...
enum class Status {
          Ready,
          Loading,
          Error
}
Q_ENUM(Status)
...

Las clases enum se registran en QML como propiedades scoped y unscoped. El valor Ready se registrará como Message.Status.Ready y Message.Ready.

Cuando se utilizan clases enum, puede haber varios enums que utilicen los mismos identificadores. El registro sin ámbito será sobrescrito por el último enum registrado. Para las clases que contengan este tipo de confictos de nombres, es posible desactivar el registro unscoped anotando su clase con una macro especial Q_CLASSINFO. Utilice el nombre RegisterEnumClassesUnscoped con el valor false para evitar que los enums scoped se fusionen en el mismo espacio de nombres.

class Message : public QObject
    {
        Q_OBJECT
        Q_CLASSINFO("RegisterEnumClassesUnscoped", "false")
        Q_ENUM(ScopedEnum)
        Q_ENUM(OtherValue)

    public:
        enum class ScopedEnum {
              Value1,
              Value2,
              OtherValue
        };
        enum class OtherValue {
              Value1,
              Value2
        };
    };

Las enumeraciones de tipos relacionados se registran normalmente en el ámbito del tipo relacionado. Por ejemplo, cualquier enum de un tipo diferente utilizado en una declaración de Q_PROPERTY hace que todos los enums de ese tipo estén disponibles en QML. Esto suele ser más un inconveniente que una característica. Para evitarlo, anote su clase con una macro especial Q_CLASSINFO. Utilice el nombre RegisterEnumsFromRelatedTypes con el valor false para evitar que los enums de tipos relacionados se registren en este tipo.

Debería registrar explícitamente los tipos adjuntos de cualquier enum que desee utilizar en QML, utilizando QML_ELEMENT o QML_NAMED_ELEMENT, en lugar de confiar en que sus enums se inyecten en otros tipos.

class OtherType : public QObject
{
    Q_OBJECT
    QML_ELEMENT

public:
    enum SomeEnum { A, B, C };
    Q_ENUM(SomeEnum)

    enum AnotherEnum { D, E, F };
    Q_ENUM(AnotherEnum)
};

class Message : public QObject
{
    Q_OBJECT
    QML_ELEMENT

    // This would usually cause all enums from OtherType to be registered
    // as members of Message ...
    Q_PROPERTY(OtherType::SomeEnum someEnum READ someEnum CONSTANT)

    // ... but this way it doesn't.
    Q_CLASSINFO("RegisterEnumsFromRelatedTypes", "false")

public:
    OtherType::SomeEnum someEnum() const { return OtherType::B; }
};

La diferencia importante es el ámbito de las enumeraciones en QML. Si un enum de una clase relacionada se registra automáticamente, el ámbito es el tipo al que se importa. En el caso anterior, sin el extra Q_CLASSINFO, se utilizaría Message.A, por ejemplo. Si el tipo C++ que contiene las sumas se registra explícitamente y se suprime el registro de sumas de tipos relacionados, el tipo QML del tipo C++ que contiene las sumas es el ámbito de todas sus sumas. En QML se utilizaría OtherType.A en lugar de Message.A.

Tenga en cuenta que puede utilizar QML_FOREIGN para registrar un tipo que no puede modificar. También puede utilizar QML_FOREIGN_NAMESPACE para registrar los enumeradores de un tipo C++ en un espacio de nombres QML de cualquier nombre en mayúsculas, incluso si el mismo tipo C++ también está registrado como tipo de valor QML.

Tipos de enumeración como parámetros de señales y métodos

Las señales y los métodos de C++ con parámetros de tipo enumeración pueden utilizarse desde QML siempre que tanto la enumeración como la señal o el método estén declarados dentro de la misma clase, o que el valor de enumeración sea uno de los declarados en Qt Namespace.

Además, si una señal C++ con un parámetro de tipo enumeración debe poder conectarse a una función QML mediante la función connect(), el tipo de enumeración debe registrarse mediante qRegisterMetaType().

Para las señales QML, los valores enum pueden pasarse como parámetros de señal utilizando el tipo int:

Message {
    signal someOtherSignal(int statusValue)

    Component.onCompleted: {
        someOtherSignal(Message.Loading)
    }
}

© 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.