Creación dinámica de objetos QML desde JavaScript
QML admite la creación dinámica de objetos desde JavaScript. Esto resulta útil para retrasar la instanciación de objetos hasta que sea necesario, mejorando así el tiempo de inicio de la aplicación. También permite crear objetos visuales de forma dinámica y añadirlos a la escena en respuesta a entradas del usuario u otros eventos.
Creación dinámica de objetos
Existen dos formas de crear objetos dinámicamente desde JavaScript. Puede llamar a Qt.createComponent() para crear dinámicamente un objeto Component, o utilizar Qt.createQmlObject() para crear un objeto a partir de una cadena de QML. La creación de un componente es mejor si tiene un componente existente definido en un documento QML y desea crear dinámicamente instancias de ese componente. De lo contrario, crear un objeto a partir de una cadena de QML es útil cuando el propio objeto QML se genera en tiempo de ejecución.
Creación dinámica de un componente
Para cargar dinámicamente un componente definido en un archivo QML, llame a la función Qt.createComponent() de Qt object. Esta función toma la URL del archivo QML como único argumento y crea un objeto Component a partir de esta URL.
Una vez que tenga un Component, puede llamar a su método createObject() para crear una instancia del componente. Esta función puede tomar uno o dos argumentos:
- El primero es el padre del nuevo objeto. El padre puede ser un objeto gráfico (es decir, del tipo Item ) o no gráfico (es decir, del tipo QtObject o C++ QObject ). Sólo se mostrarán en el lienzo visual los objetos gráficos cuyo padre sea un objeto gráfico. Qt Quick lienzo visual. Si desea establecer el padre más tarde, puede pasar
nulla esta función. - El segundo es opcional y es un mapa de pares propiedad-valor que definen los valores iniciales de cualquier propiedad para el objeto. Los valores de propiedad especificados por este argumento se aplican al objeto antes de que finalice su creación, evitando errores de vinculación que pueden producirse si determinadas propiedades deben inicializarse para permitir otras vinculaciones de propiedades. Además, existen pequeñas ventajas de rendimiento en comparación con la definición de valores de propiedad y vinculaciones después de la creación del objeto.
He aquí un ejemplo. En primer lugar, Sprite.qml, que define un componente QML sencillo:
import QtQuick Rectangle { width: 80; height: 50; color: "red" }
Nuestro archivo de aplicación principal, main.qml, importa un archivo JavaScript componentCreation.js que creará objetos Sprite:
import QtQuick import "componentCreation.js" as MyScript Rectangle { id: appWindow width: 300; height: 300 Component.onCompleted: MyScript.createSpriteObjects(); }
Aquí está componentCreation.js. Observe que comprueba si el componente status es Component.Ready antes de llamar a createObject() en caso de que el archivo QML se cargue a través de una red y, por tanto, no esté listo inmediatamente.
var component;
var sprite;
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
if (component.status == Component.Ready)
finishCreation();
else
component.statusChanged.connect(finishCreation);
}
function finishCreation() {
if (component.status == Component.Ready) {
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
} else if (component.status == Component.Error) {
// Error Handling
console.log("Error loading component:", component.errorString());
}
}Si está seguro de que el archivo QML que se va a cargar es un archivo local, puede omitir la función finishCreation() y llamar inmediatamente a createObject():
function createSpriteObjects() {
component = Qt.createComponent("Sprite.qml");
sprite = component.createObject(appWindow, {x: 100, y: 100});
if (sprite == null) {
// Error Handling
console.log("Error creating object");
}
}Observe que en ambos casos se llama a createObject() con appWindow como argumento padre, ya que el objeto creado dinámicamente es un objeto visual (Qt Quick). El objeto creado se convertirá en hijo del objeto appWindow en main.qml, y aparecerá en la escena.
Cuando se utilizan archivos con rutas relativas, la ruta debe ser relativa al archivo donde se ejecuta Qt.createComponent().
Para conectar señales a (o recibir señales de) objetos creados dinámicamente, utilice el método de señal connect(). Consulte Conexión de señales a métodos y señales para obtener más información.
También es posible instanciar componentes sin bloqueo mediante la función incubateObject().
Creación de un objeto a partir de una cadena de QML
Advertencia: Crear objetos a partir de una cadena QML es extremadamente lento ya que el motor tiene que compilar la cadena QML pasada cada vez que lo haces. Además, es muy fácil producir QML inválido cuando se construye código QML mediante programación. Es mucho mejor mantener los componentes QML como archivos separados y añadir propiedades y métodos para personalizar su comportamiento que producir nuevos componentes mediante la manipulación de cadenas.
Si el QML no se define hasta el tiempo de ejecución, puede crear un objeto QML a partir de una cadena de QML utilizando la función Qt.createQmlObject(), como en el ejemplo siguiente:
const newObject = Qt.createQmlObject(` import QtQuick Rectangle { color: "red" width: 20 height: 20 } `, parentItem, "myDynamicSnippet" );
El primer argumento es la cadena de QML a crear. Al igual que en un archivo nuevo, deberá importar los tipos que desee utilizar. El segundo argumento es el objeto padre para el nuevo objeto, y la semántica del argumento padre que se aplica a los componentes es igualmente aplicable a createQmlObject(). El tercer argumento es la ruta del archivo a asociar con el nuevo objeto; se utiliza para la notificación de errores.
Si la cadena de QML importa archivos utilizando rutas relativas, la ruta debe ser relativa al archivo en el que está definido el objeto padre (el segundo argumento del método).
Importante: Cuando se construyen aplicaciones QML estáticas, los archivos QML se analizan para detectar dependencias de importación. De esta forma, todos los plugins y recursos necesarios se resuelven en tiempo de compilación. Sin embargo, sólo se tienen en cuenta las sentencias import explícitas (las que se encuentran en la parte superior de un archivo QML), y no las sentencias import encerradas en literales de cadena. Por lo tanto, para soportar compilaciones estáticas, debe asegurarse de que los archivos QML que utilicen Qt.createQmlObject() contengan explícitamente todas las importaciones necesarias en la parte superior del archivo, además de dentro de los literales de cadena.
Mantenimiento de objetos creados dinámicamente
Al gestionar objetos creados dinámicamente, debe asegurarse de que el contexto de creación sobreviva al objeto creado. De lo contrario, si el contexto de creación se destruye primero, las vinculaciones y los manejadores de señales del objeto dinámico dejarán de funcionar.
El contexto de creación real depende de cómo se crea un objeto:
- Si se utiliza Qt.createComponent(), el contexto de creación es el QQmlContext en el que se llama a este método.
- Si se llama a Qt.createQmlObject(), el contexto de creación es el contexto del objeto padre pasado a este método.
- Si se define un objeto
Component{}y se llama a createObject() o incubateObject() en ese objeto, el contexto de creación es el contexto en el que se defineComponent.
Además, tenga en cuenta que aunque los objetos creados dinámicamente se pueden utilizar igual que otros objetos, no tienen un id en QML.
Eliminación dinámica de objetos
En muchas interfaces de usuario, basta con establecer la opacidad de un objeto visual en 0 o mover el objeto visual fuera de la pantalla en lugar de eliminarlo. Sin embargo, si tiene muchos objetos creados dinámicamente, puede obtener una ventaja de rendimiento si elimina los objetos no utilizados.
Tenga en cuenta que nunca debe eliminar manualmente los objetos creados dinámicamente por las fábricas de objetos QML (como Loader y Repeater). Asimismo, debe evitar eliminar objetos que no haya creado usted mismo de forma dinámica.
Los elementos se pueden eliminar mediante el método destroy(). Este método tiene un argumento opcional (que por defecto es 0) que especifica el retardo aproximado en milisegundos antes de que el objeto sea destruido.
He aquí un ejemplo. El application.qml crea cinco instancias del componente SelfDestroyingRect.qml. Cada instancia ejecuta un NumberAnimation, y cuando la animación ha terminado, llama a destroy() en su objeto raíz para destruirse:
application.qml | import QtQuick Item { id: container width: 500; height: 100 Component.onCompleted: { var component = Qt.createComponent("SelfDestroyingRect.qml"); for (var i=0; i<5; i++) { var object = component.createObject(container); object.x = (object.width + 10) * i; } } } |
SelfDestroyingRect.qml | import QtQuick Rectangle { id: rect width: 80; height: 80 color: "red" NumberAnimation on opacity { to: 0 duration: 1000 onRunningChanged: { if (!running) { console.log("Destroying...") rect.destroy(); } } } } |
Alternativamente, el application.qml podría haber destruido el objeto creado llamando a object.destroy().
Tenga en cuenta que es seguro llamar a destroy() en un objeto dentro de ese objeto. Los objetos no se destruyen en el instante en que se llama a destroy(), sino que se limpian en algún momento entre el final de ese bloque de script y el siguiente fotograma (a menos que hayas especificado un retardo distinto de cero).
Tenga en cuenta también que si una instancia de SelfDestroyingRect se creara estáticamente de esta manera:
Item { SelfDestroyingRect { // ... } }
Esto resultaría en un error, ya que los objetos sólo pueden ser destruidos dinámicamente si fueron creados dinámicamente.
Los objetos creados con Qt.createQmlObject() también pueden destruirse con destroy():
const newObject = Qt.createQmlObject(` import QtQuick Rectangle { color: "red" width: 20 height: 20 } `, parentItem, "myDynamicSnippet" ); newObject.destroy(1000);
© 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.