Interacción con objetos QML desde C++
Todos los tipos de objetos QML son tipos derivados de QObject, ya estén implementados internamente por el motor o definidos por fuentes de terceros. Esto significa que el motor QML puede utilizar el sistema de metaobjetos de Qt para instanciar dinámicamente cualquier tipo de objeto QML e inspeccionar los objetos creados.
Esto resulta útil para crear objetos QML a partir de código C++, ya sea para mostrar un objeto QML que pueda representarse visualmente o para integrar datos de objetos QML no visuales en una aplicación C++. Una vez creado un objeto QML, puede inspeccionarse desde C++ para leer y escribir en propiedades, invocar métodos y recibir notificaciones de señales.
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.
Carga de objetos QML desde C
Un documento QML puede cargarse con QQmlComponent o QQuickView. QQmlComponent carga un documento QML como un objeto C++ que puede modificarse a continuación desde código C++. QQuickView también hace esto, pero como QQuickView es una clase derivada de QWindow, el objeto cargado también se representará en una pantalla visual; QQuickView se utiliza generalmente para integrar un objeto QML visualizable en la interfaz de usuario de una aplicación.
Por ejemplo, supongamos que existe un archivo MyItem.qml con el siguiente aspecto:
import QtQuick Item { width: 100; height: 100 }
Este documento QML puede cargarse con QQmlComponent o QQuickView con el siguiente código C++. El uso de un QQmlComponent requiere llamar a QQmlComponent::create() para crear una nueva instancia del componente, mientras que un QQuickView crea automáticamente una instancia del componente, a la que se puede acceder a través de QQuickView::rootObject():
// Using QQmlComponent QQmlEngine engine; QQmlComponent component(&engine, QUrl::fromLocalFile("MyItem.qml")); QObject *object = component.create(); ... delete object; | // Using QQuickView QQuickView view; view.setSource(QUrl::fromLocalFile("MyItem.qml")); view.show(); QObject *object = view.rootObject(); |
Este object es la instancia del componente MyItem.qml que se ha creado. Ahora puede modificar las propiedades del elemento mediante QObject::setProperty() o QQmlProperty::write():
object->setProperty("width", 500); QQmlProperty(object, "width").write(500);
La diferencia entre QObject::setProperty() y QQmlProperty::write() es que este último también eliminará el binding además de establecer el valor de la propiedad. Por ejemplo, supongamos que la asignación width anterior hubiera sido un enlace a height:
width: height
Si el height del Item cambiara después de la llamada a object->setProperty("width", 500), el width se actualizaría de nuevo, ya que el binding permanece activo. Sin embargo, si el height cambia después de la llamada a QQmlProperty(object, "width").write(500), el width no se modificará, ya que el binding ya no existe.
Alternativamente, puedes convertir el objeto a su tipo real y llamar a métodos con seguridad en tiempo de compilación. En este caso, el objeto base de MyItem.qml es un Item, definido por la clase QQuickItem:
QQuickItem *item = qobject_cast<QQuickItem*>(object); item->setWidth(500);
También puede conectarse a cualquier señal o llamar a métodos definidos en el componente utilizando QMetaObject::invokeMethod() y QObject::connect(). Consulte Invocar métodos QML y Conectarse a señales QML más adelante para obtener más detalles.
Acceso a objetos QML a través de interfaces C++ bien definidas
La mejor forma de interactuar con QML desde C++ es definir una interfaz para hacerlo en C++ y acceder a ella en el propio QML. Con otros métodos, refactorizar el código QML puede llevar fácilmente a romper la interacción QML / C++. También ayuda a razonar sobre la interacción de QML y el código C++, ya que si se maneja a través de QML puede ser más fácilmente razonado tanto por los usuarios como por herramientas como qmllint. Acceder a QML desde C++ conducirá a código QML que no puede entenderse sin verificar manualmente que ningún código C++ externo está modificando un componente QML dado, e incluso entonces el alcance del acceso podría cambiar con el tiempo, haciendo que el uso continuado de esta estrategia sea una carga de mantenimiento.
Para que QML dirija la interacción, primero hay que definir una interfaz C++:
class CppInterface : public QObject { Q_OBJECT QML_ELEMENT // ... };
Utilizando un enfoque basado en QML, se puede interactuar con esta interfaz de dos maneras:
Singletons
Una opción es registrar la interfaz como singleton añadiendo la macro QML_SINGLETON a la interfaz, exponiéndola a todos los componentes. A continuación, la interfaz estará disponible mediante una simple sentencia import:
import my.company.module Item { Component.onCompleted: { CppInterface.foo(); } }
Utilice este método si necesita su interfaz en más lugares que el componente raíz, ya que simplemente pasar un objeto requeriría pasarlo explícitamente a otros componentes a través de una propiedad o utilizar el método lento y no recomendado de utilizar el acceso no cualificado.
Propiedades iniciales
Otra opción es marcar la interfaz como no creable a través de QML_UNCREATABLE y suministrarla al componente QML raíz utilizando QQmlComponent::createWithInitialProperties() y una propiedad requerida en el extremo QML.
Tu componente raíz puede tener este aspecto
import QtQuick
Item {
required property CppInterface interface
Component.onCompleted: {
interface.foo();
}
}Marcar la propiedad como requerida aquí protege el componente contra su creación sin que la propiedad de interfaz esté establecida.
A continuación, puede inicializar el componente de la misma forma que se describe en Carga de objetos QML desde C++, excepto que utiliza createWithInitialProperties():
component.createWithInitialProperties(QVariantMap{{u"interface"_s, QVariant::fromValue<CppInterface *>(new CppInterface)}});
Este método es preferible si sabe que su interfaz sólo necesita estar disponible para el componente raíz. También permite conectarse a señales y ranuras de la interfaz más fácilmente en el lado C++.
Si ninguno de estos métodos se ajusta a sus necesidades, puede que desee investigar el uso de modelos C++ en su lugar.
Acceso a objetos QML cargados por nombre de objeto
Los componentes QML son esencialmente árboles de objetos con hijos que tienen hermanos y sus propios hijos. Los objetos hijos de los componentes QML pueden localizarse utilizando la propiedad QObject::objectName con QObject::findChild(). Por ejemplo, si el elemento raíz de MyItem.qml tuviera un elemento hijo Rectangle:
import QtQuick Item { width: 100; height: 100 Rectangle { anchors.fill: parent objectName: "rect" } }
El hijo podría localizarse así:
Nótese que un objeto puede tener múltiples hijos con el mismo objectName. Por ejemplo, ListView crea múltiples instancias de su delegado, por lo que si su delegado se declara con un objectName particular, el ListView tendrá múltiples hijos con el mismo objectName. En este caso, se puede utilizar QObject::findChildren() para encontrar todos los hijos con un objectName coincidente.
Advertencia: Aunque es posible acceder a objetos QML desde C++ y manipularlos, no es el método recomendado, excepto para pruebas y prototipos. Uno de los puntos fuertes de la integración de QML y C++ es la posibilidad de implementar interfaces de usuario en QML separadas de la lógica de C++ y del backend del conjunto de datos, y esto falla si la parte de C++ empieza a manipular QML directamente. Este enfoque también dificulta el cambio de la interfaz de usuario de QML sin afectar a su homóloga de C++.
Acceso a los miembros de un tipo de objeto QML desde C++
Propiedades
Cualquier propiedad declarada en un objeto QML es accesible automáticamente desde C++. Dado un objeto QML como este
El valor de la propiedad someNumber puede establecerse y leerse utilizando QQmlProperty, o QObject::setProperty() y QObject::property():
QQmlEngine motor;QQmlComponent component(&engine, "MiItem.qml");QObject *object = component.create(); qDebug() << "Property value:" << QQmlProperty::read(object, "someNumber").toInt(); QQmlProperty::write(objeto, "algunNúmero", 5000); qDebug() << "Property value:" << object->property("someNumber").toInt(); object->setProperty("algunNumero", 100);
Siempre debe utilizar QObject::setProperty(), QQmlProperty o QMetaProperty::write() para cambiar el valor de una propiedad QML, para asegurarse de que el motor QML es consciente del cambio de propiedad. Por ejemplo, supongamos que tiene un tipo personalizado PushButton con una propiedad buttonText que refleja internamente el valor de una variable miembro m_buttonText. Modificar directamente la variable miembro no es una buena idea:
//bad code QQmlComponent component(engine, "MyButton.qml"); PushButton *button = qobject_cast<PushButton*>(component.create()); button->m_buttonText = "Click me";
Dado que el valor se cambia directamente, esto evita el sistema de meta-objetos de Qt y el motor QML no es consciente del cambio de propiedad. Esto significa que las propiedades vinculadas a buttonText no se actualizarán, y que no se llamará a ningún gestor de onButtonTextChanged.
Invocación de métodos QML
Todos los métodos QML están expuestos al sistema de metaobjetos y pueden invocarse desde C++ utilizando QMetaObject::invokeMethod(). Puede especificar tipos para los parámetros y el valor de retorno después del carácter dos puntos, como se muestra en el siguiente fragmento de código. Esto puede ser útil, por ejemplo, cuando se desea conectar una señal en C++ con una determinada firma a un método definido por QML. Si omite los tipos, la firma C++ utilizará QVariant.
He aquí una aplicación C++ que llama a un método QML utilizando QMetaObject::invokeMethod():
| QML | // MyItem.qml import QtQuick Item { function myQmlFunction(msg: string) : string { console.log("Got message:", msg) return "some return value" } } |
| C++ | // main.cppQQmlEngine motor;QQmlComponent component(&engine, "MiItem.qml");QObject *object = component.create();QString returnedValue;QString msg = "Hola desde C++";QMetaObject::invokeMethod(object, "myQmlFunction",Q_RETURN_ARG(QString, returnedValue),Q_ARG(QString, msg)); qDebug() << "QML function returned:" << returnedValue; borrar objeto; |
Observe el parámetro y el tipo de retorno especificados después de los dos puntos. Puede utilizar tipos de valor y tipos de objeto como nombres de tipo.
Si el tipo se omite o se especifica como var en QML, entonces debe pasar QVariant como tipo con Q_RETURN_ARG() y Q_ARG() al llamar a QMetaObject::invokeMethod.
Conexión a señales QML
Todas las señales QML están automáticamente disponibles para C++, y se puede conectar a ellas utilizando QObject::connect() como a cualquier señal C++ normal de Qt. A su vez, cualquier señal C++ puede ser recibida por un objeto QML utilizando manejadores de señales.
A continuación se muestra un componente QML con una señal denominada qmlSignal que se emite con un parámetro de tipo cadena. Esta señal está conectada al slot de un objeto C++ mediante QObject::connect(), de forma que el método cppSlot() es llamado cada vez que se emite qmlSignal:
clase MyClass : public QObject { Q_OBJECTpublic slots: void cppSlot(const QString &msg) { qDebug() << "Called the C++ slot with message:" << msg; } };int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView view(QUrl::fromLocalFile("MiItem.qml")); QObject *item = view.rootObject(); MyClass myClass; QObject::connect(item, SIGNAL(qmlSignal(QString)), &myClass, SLOT(cppSlot(QString))); view.show(); return app.exec(); } |
Un tipo de objeto QML en un parámetro de señal se traduce a un puntero a la clase en C++:
clase MiClase : public QObject { Q_OBJECT ranuraspúblicas: void cppSlot(QQuickItem *item) { qDebug() << "Called the C++ slot with item:" << item; qDebug() << "Item dimensions:" << item->width() << item->height(); } };int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QQuickView vista(QUrl::fromLocalFile("MiItem.qml")); QObject *item = view.rootObject(); MyClass myClass; QObject::connect(item, SIGNAL(qmlSignal(QVariant)), &myClass, SLOT(cppSlot(QVariant))); view.show(); return app.exec(); } |
© 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.