Sur cette page

Création dynamique d’objets QML à partir de JavaScript

QML prend en charge la création dynamique d'objets à partir de JavaScript. Cela permet de différer l'instanciation des objets jusqu'à ce qu'elle soit nécessaire, améliorant ainsi le temps de démarrage de l'application. Cela permet également de créer dynamiquement des objets visuels et de les ajouter à la scène en réponse à une action de l'utilisateur ou à d'autres événements.

Avertissement : les objets ne doivent pas être créés dynamiquement à partir de sources non fiables. Les restrictions applicables aux sources QML statiques s’appliquent également à la création dynamique d’objets.

Création dynamique d’objets

Il existe deux façons de créer des objets de manière dynamique à partir de JavaScript. Vous pouvez soit appeler ` Qt.createComponent()` pour créer dynamiquement un objet ` Component `, soit utiliser ` Qt.createQmlObject()` pour créer un objet à partir d’une chaîne de caractères QML. La création d’un composant est préférable si vous disposez d’un composant existant défini dans un document QML et que vous souhaitez créer dynamiquement des instances de ce composant. Sinon, la création d’un objet à partir d’une chaîne de code QML est utile lorsque le code QML de l’objet lui-même est généré lors de l’exécution.

Création dynamique d’un composant

Pour charger dynamiquement un composant défini dans un fichier QML, appelez la fonction ` Qt.createComponent()` de la classe ` Qt object`. Cette fonction prend l’URL du fichier QML comme seul argument et crée un objet ` Component ` à partir de cette URL.

Une fois que vous disposez d’un ` Component`, vous pouvez appeler sa méthode ` createObject()` pour créer une instance du composant. Cette fonction peut prendre un ou deux arguments :

  • Le premier est le parent du nouvel objet. Le parent peut être un objet graphique (c'est-à-dire de type ` Item `) ou un objet non graphique (c'est-à-dire de type ` QtObject ` ou `C++ QObject `). Seuls les objets graphiques dont les objets parents sont également graphiques seront affichés sur le Qt Quick canevas visuel. Si vous souhaitez définir le parent ultérieurement, vous pouvez sans risque passer ` null ` à cette fonction.
  • Le deuxième argument est facultatif ; il s’agit d’une carte de paires propriété-valeur qui définissent les valeurs initiales de n’importe quelle propriété de l’objet. Les valeurs de propriété spécifiées par cet argument sont appliquées à l’objet avant que sa création ne soit finalisée, ce qui évite les erreurs de liaison pouvant survenir si certaines propriétés doivent être initialisées pour permettre la liaison d’autres propriétés. De plus, cela apporte de légers gains de performances par rapport à la définition des valeurs de propriétés et des liaisons après la création de l’objet.

Voici un exemple. Il y a tout d’abord Sprite.qml, qui définit un composant QML simple :

import QtQuick

Rectangle { width: 80; height: 50; color: "red" }

Notre fichier d’application principal, main.qml, importe un fichier JavaScript componentCreation.js qui créera des objets Sprite:

import QtQuick
import "componentCreation.js" as MyScript

Rectangle {
    id: appWindow
    width: 300; height: 300

    Component.onCompleted: MyScript.createSpriteObjects();
}

Voici le fichier componentCreation.js. Notez qu’il vérifie si le composant status est bien Component.Ready avant d’appeler createObject(), au cas où le fichier QML serait chargé via le réseau et ne serait donc pas immédiatement prêt.

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 vous êtes certain que le fichier QML à charger est un fichier local, vous pouvez omettre la fonction finishCreation() et appeler createObject() immédiatement :

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");
    }
}

Notez que dans les deux cas, la fonction ` createObject()` est appelée avec ` appWindow ` passé en argument parent, car l’objet créé dynamiquement est un objet visuel (Qt Quick). L’objet créé deviendra un enfant de l’objet ` appWindow ` dans ` main.qml` et apparaîtra dans la scène.

Lorsque vous utilisez des fichiers avec des chemins relatifs, le chemin doit être relatif au fichier dans lequel la fonction Qt.createComponent() est exécutée.

Pour connecter des signaux à des objets créés dynamiquement (ou recevoir des signaux de ceux-ci), utilisez la méthode ` connect() `. Pour plus d’informations, consultez la section « Connexion de signaux à des méthodes et à des signaux ».

Il est également possible d’instancier des composants sans blocage via la fonction ` incubateObject()`.

Création d’un objet à partir d’une chaîne de caractères QML

Avertissement : la création d’objets à partir d’une chaîne de caractères QML est extrêmement lente, car le moteur doit compiler la chaîne QML transmise à chaque fois que vous effectuez cette opération. De plus, il est très facile de générer du code QML invalide lors de la construction programmatique de code QML. Il est préférable de conserver vos composants QML dans des fichiers séparés et d’ajouter des propriétés et des méthodes pour personnaliser leur comportement plutôt que de créer de nouveaux composants par manipulation de chaînes de caractères.

Si le code QML n’est pas défini avant l’exécution, vous pouvez créer un objet QML à partir d’une chaîne de code QML à l’aide de la fonction ` Qt.createQmlObject()`, comme dans l’exemple suivant :

const newObject = Qt.createQmlObject(`
    import QtQuick

    Rectangle {
        color: "red"
        width: 20
        height: 20
    }
    `,
    parentItem,
    "myDynamicSnippet"
);

Le premier argument est la chaîne de code QML à créer. Tout comme dans un nouveau fichier, vous devrez importer tous les types que vous souhaitez utiliser. Le deuxième argument est l’objet parent du nouvel objet, et la sémantique de l’argument « parent » qui s’applique aux composants s’applique de la même manière à createQmlObject(). Le troisième argument est le chemin d’accès au fichier à associer au nouvel objet ; il est utilisé pour le signalement des erreurs.

Si la chaîne de code QML importe des fichiers à l’aide de chemins relatifs, ceux-ci doivent être relatifs au fichier dans lequel l’objet parent (le deuxième argument de la méthode) est défini.

Important : lors de la compilation d’applications QML statiques, les fichiers QML sont analysés pour détecter les dépendances d’importation. Ainsi, tous les plugins et ressources nécessaires sont résolus au moment de la compilation. Cependant, seules les instructions d’importation explicites sont prises en compte (celles figurant en début de fichier QML), et non celles incluses dans des littéraux de chaîne. Pour prendre en charge les compilations statiques, vous devez donc vous assurer que les fichiers QML utilisant ` Qt.createQmlObject()` contiennent explicitement toutes les importations nécessaires en début de fichier, en plus de celles figurant à l’intérieur des littéraux de chaîne.

Gestion des objets créés dynamiquement

Lors de la gestion d’objets créés dynamiquement, vous devez vous assurer que le contexte de création survit à l’objet créé. Sinon, si le contexte de création est détruit en premier, les liaisons et les gestionnaires de signaux de l’objet dynamique ne fonctionneront plus.

Le contexte de création réel dépend de la manière dont un objet est créé :

  • Si la méthode ` Qt.createComponent()` est utilisée, le contexte de création est l’ QQmlContext e dans laquelle cette méthode est appelée
  • Si la méthode ` Qt.createQmlObject()` est appelée, le contexte de création est celui de l’objet parent transmis à cette méthode
  • Si un objet ` Component{} ` est défini et que ` createObject()` ou ` incubateObject()` est appelé sur cet objet, le contexte de création est le contexte dans lequel l’` Component ` est défini

Notez également que, bien que les objets créés dynamiquement puissent être utilisés de la même manière que les autres objets, ils ne possèdent pas d’identifiant (id) en QML.

Suppression dynamique d’objets

Dans de nombreuses interfaces utilisateur, il suffit de définir l’opacité d’un objet visuel sur 0 ou de le déplacer hors de l’écran plutôt que de le supprimer. Si vous disposez toutefois d’un grand nombre d’objets créés dynamiquement, la suppression des objets inutilisés peut apporter un gain de performances significatif.

Notez que vous ne devez jamais supprimer manuellement des objets créés dynamiquement par des fabriques d’objets QML de commodité (telles que Loader et Repeater). De même, vous devez éviter de supprimer des objets que vous n’avez pas créés dynamiquement vous-même.

Les éléments peuvent être supprimés à l’aide de la méthode ` destroy() `. Cette méthode dispose d’un argument facultatif (dont la valeur par défaut est 0) qui spécifie le délai approximatif, en millisecondes, avant la destruction de l’objet.

Voici un exemple. La méthode ` application.qml ` crée cinq instances du composant ` SelfDestroyingRect.qml `. Chaque instance exécute une animation via ` NumberAnimation`, et une fois l’animation terminée, elle appelle la méthode ` destroy() ` sur son objet racine pour se détruire :

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();
            }
        }
    }
}

Sinon, le fichier « application.qml » aurait pu détruire l’objet créé en appelant ` object.destroy()`.

Notez qu’il est sans risque d’appeler `destroy()` sur un objet à l’intérieur de cet objet. Les objets ne sont pas détruits dès l’appel de `destroy()`, mais sont nettoyés à un moment donné entre la fin de ce bloc de script et l’image suivante (à moins que vous n’ayez spécifié un délai non nul).

Notez également que si une instance d’ SelfDestroyingRect a été créée de manière statique comme ceci :

Item {
    SelfDestroyingRect {
        // ...
    }
}

Cela entraînerait une erreur, car les objets ne peuvent être détruits dynamiquement que s’ils ont été créés dynamiquement.

Les objets créés avec ` Qt.createQmlObject()` peuvent de la même manière être détruits à l’aide de ` 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.