Sur cette page

Portée et résolution des noms

Les liaisons de propriétés QML, les fonctions en ligne et les fichiers JavaScript importés s'exécutent tous dans une portée JavaScript. La portée contrôle les variables auxquelles une expression peut accéder et la variable qui a la priorité en cas de conflit entre deux ou plusieurs noms.

Le mécanisme de portée intégré à JavaScript étant très simple, QML l'améliore pour qu'il s'intègre plus naturellement aux extensions du langage QML.

Champ d'application JavaScript

Les extensions de portée de QML n'interfèrent pas avec la portée naturelle de JavaScript. Les programmeurs JavaScript peuvent réutiliser leurs connaissances existantes lorsqu'ils programment des fonctions, des liaisons de propriétés ou des fichiers JavaScript importés en QML.

Dans l'exemple suivant, la méthode addConstant() ajoutera 13 au paramètre transmis, comme le programmeur s'y attendrait, quelle que soit la valeur des propriétés a et b de l'objet QML.

QtObject {
    property int a: 3
    property int b: 9

    function addConstant(b) {
        var a = 13;
        return b + a;
    }
}

Le fait que QML respecte les règles de portée normales de JavaScript s'applique également aux liaisons. Cette abomination de liaison totalement diabolique attribuera 12 à la propriété a de l'objet QML.

QtObject {
    property int a

    a: { var a = 12; a; }
}

Chaque expression, fonction ou fichier JavaScript dans QML possède son propre objet variable unique. Les variables locales déclarées dans l'une d'elles n'entreront jamais en conflit avec les variables locales déclarées dans une autre.

Noms de type et fichiers JavaScript importés

Lesdocuments QML comprennent des instructions d'importation qui définissent les noms de types et les fichiers JavaScript visibles dans le document. Outre leur utilisation dans la déclaration QML elle-même, les noms de type sont utilisés par le code JavaScript lorsqu'il accède aux propriétés attachées et aux valeurs d'énumération.

L'effet d'une importation s'applique à chaque liaison de propriété et à chaque fonction JavaScript dans le document QML, même celles qui se trouvent dans des composants en ligne imbriqués. L'exemple suivant montre un simple fichier QML qui accède à certaines valeurs d'énumération et appelle une fonction JavaScript importée.

import QtQuick 2.0
import "code.js" as Code

ListView {
    snapMode: ListView.SnapToItem

    delegate: Component {
        Text {
            elide: Text.ElideMiddle
            text: "A really, really long string that will require eliding."
            color: Code.defaultColor()
        }
    }
}

Objet à portée de liaison

Un objet dont la propriété est liée est connu sous le nom d'objet de portée de la liaison. Dans l'exemple suivant, l'objet Item est l'objet de portée de la liaison.

Item {
    anchors.left: parent.left
}

Les liaisons ont accès aux propriétés de l'objet scope sans aucune restriction. Dans l'exemple précédent, le binding accède directement à la propriété parent de Item, sans avoir besoin d'un quelconque préfixe d'objet. QML introduit une approche plus structurée et orientée objet de JavaScript et, par conséquent, ne nécessite pas l'utilisation de la propriété JavaScript this.

Il convient d'être prudent lors de l'accès aux propriétés attachées à partir des liaisons en raison de leur interaction avec l'objet de portée. Conceptuellement, les propriétés attachées existent sur tous les objets, même si elles n'ont d'effet que sur un sous-ensemble d'entre eux. Par conséquent, les lectures de propriétés attachées non qualifiées seront toujours résolues à une propriété attachée sur l'objet scope, ce qui n'est pas toujours ce que le programmeur a voulu.

Par exemple, le type PathView attache des propriétés de valeur interpolées à ses délégués en fonction de leur position dans le chemin. Comme PathView n'attache ces propriétés qu'à l'objet racine du délégué, tout sous-objet qui y accède doit explicitement qualifier l'objet racine, comme indiqué ci-dessous.

PathView {
    delegate: Component {
        Rectangle {
            id: root
            Image {
                scale: root.PathView.scale
            }
        }
    }
}

Si l'objet Image omettait le préfixe root, il accéderait par inadvertance à la propriété attachée PathView.scale non définie sur lui-même.

Portée des composants

Chaque composant QML d'un document QML définit une portée logique. Chaque document possède au moins un composant racine, mais peut également avoir d'autres sous-composants en ligne. La portée du composant est l'union des identifiants des objets au sein du composant et des propriétés de l'objet racine du composant.

Item {
    property string title

    Text {
        id: titletype
        text: "<b>" + title + "</b>"
        font.pixelSize: 22
        anchors.top: parent.top
    }

    Text {
        text: titletype.text
        font.pixelSize: 18
        anchors.bottom: parent.bottom
    }
}

L'exemple ci-dessus montre un composant QML simple qui affiche une chaîne de titre en texte riche en haut et une copie plus petite du même texte en bas. Le premier type Text accède directement à la propriété title du composant lorsqu'il forme le texte à afficher. Le fait que les propriétés du type racine soient directement accessibles facilite la distribution des données dans l'ensemble du composant.

Le deuxième type Text utilise un identifiant pour accéder directement au texte du premier. Les identifiants sont spécifiés explicitement par le programmeur QML et ont donc toujours la priorité sur les autres noms de propriétés (à l'exception de ceux de la portée JavaScript). Par exemple, dans le cas improbable où l'objet scope du binding aurait une propriété titletype dans l'exemple précédent, l'identifiant titletype serait toujours prioritaire.

Hiérarchie des instances de composants

En QML, les instances de composants relient leurs champs d'application pour former une hiérarchie de champs d'application. Les instances de composants peuvent accéder directement à la portée des composants de leurs ancêtres.

La façon la plus simple de le démontrer est d'utiliser des sous-composants en ligne dont les portées de composants sont implicitement considérées comme des enfants du composant extérieur.

Item {
    property color defaultColor: "blue"

    ListView {
        delegate: Component {
            Rectangle {
                color: defaultColor
            }
        }
    }
}

La hiérarchie des instances de composants permet aux instances du composant délégué d'accéder à la propriété defaultColor du type Item. Bien entendu, si le composant délégué avait eu une propriété appelée defaultColor, celle-ci aurait eu la priorité.

La hiérarchie des instances de composants s'étend également aux composants hors ligne. Dans l'exemple suivant, le composant TitlePage.qml crée deux instances TitleText. Même si le type TitleText se trouve dans un fichier distinct, il a toujours accès à la propriété title lorsqu'il est utilisé à partir de TitlePage. QML est un langage à portée dynamique - selon l'endroit où il est utilisé, la propriété title peut être résolue différemment.

// TitlePage.qml
import QtQuick 2.0
Item {
    property string title

    TitleText {
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property int size
    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

Le cadrage dynamique est très puissant, mais il doit être utilisé avec prudence pour éviter que le comportement du code QML ne devienne difficile à prévoir. En général, il ne devrait être utilisé que dans les cas où les deux composants sont déjà étroitement couplés d'une autre manière. Lors de la construction de composants réutilisables, il est préférable d'utiliser des interfaces de propriété, comme ceci :

// TitlePage.qml
import QtQuick 2.0
Item {
    id: root
    property string title

    TitleText {
        title: root.title
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        title: root.title
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property string title
    property int size

    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

Ne pas référencer l'objet racine id à partir d'autres composants QML

Évitez d'accéder à id d'un objet racine en dehors du fichier QML dans lequel il est défini. Les valeurs de id ne sont valables qu'au sein du même document, et le fait de s'y référer à partir d'autres composants rompt l'encapsulation et les limites des composants.

// Main.qml
import QtQuick

Item {
    id: root
    CustomItem { }
}

// CustomItem.qml
import QtQuick

Rectangle {
    width: root.width
    height: root.height / 2
    color: "red"
}

Dans l'exemple ci-dessus, root n'est pas déclaré dans CustomItem.qml. Le code fonctionne toujours car CustomItem est instancié dans un contexte où root existe, ce qui est autorisé par les règles de cadrage dynamique de QML. Cependant, cela crée une dépendance implicite sur la portée extérieure, ce qui rend le composant peu fiable et plus difficile à réutiliser lorsqu'il est chargé dynamiquement ou utilisé dans un contexte différent. Ce modèle peut également entraîner des bogues subtils. Par exemple, si un autre objet de la chaîne de portée utilise le même id, il peut masquer celui qui est attendu, ce qui entraîne un comportement inattendu.

Pour rendre les composants fiables et réutilisables, n'accédez à l'état externe que par le biais de propriétés explicites, d'alias de propriétés ou de signaux. Évitez de vous fier aux valeurs de id dans le cadre externe.

L'exemple suivant remplace le cadrage dynamique par une API de composant explicite.

// Main.qml
import QtQuick
import QtQuick.Window

Window {
    id: root
    width: 400
    height: 300
    visible: true

    CustomItem {
        width: root.width
        height: root.height
        boxColor: "blue"
    }
}

// CustomItem.qml
import QtQuick

Item {
    id: container
    property alias boxColor: rect.color

    Rectangle {
        id: rect
        width: container.width
        height: container.height / 2
        color: "red"
    }
}

Appliquez la même règle à tous les objets internes déclarés avec id à l'intérieur d'un composant.

// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCounter.count);
    }
}

Dans l'exemple ci-dessus, l'accès à id internalCounter à partir d'un autre fichier QML provoque un ReferenceError car un id est local au document et ne peut être accédé en dehors du fichier QML dans lequel il est déclaré.

Si un objet interne doit exposer son état ou son comportement, il doit le faire explicitement par le biais de propriétés, d'alias de propriétés ou de signaux.

L'exemple suivant expose l'état interne par le biais d'une API de composant explicite au lieu de s'appuyer sur un accès direct à un document local id.

// MyItem.qml
import QtQuick

Item {
    Item {
        id: internalCounter
        property int count: 5
    }
    property alias internalCount: internalCounter.count
}

// main.qml
import QtQuick

MyItem {
    Component.onCompleted: {
        console.log(internalCount);
    }
}

Cela permet de maintenir des limites claires entre les composants et d'améliorer l'évolutivité et la testabilité.

Propriétés superposées

QML permet aux noms de propriétés définis dans une déclaration d'objet d'être remplacés par des propriétés déclarées dans une autre déclaration d'objet qui étend la première. En voici un exemple :

// Displayable.qml
import QtQuick 2.0
Item {
    property string title
    property string detail

    Text {
        text: "<b>" + title + "</b><br>" + detail
    }

    function getTitle() { return title }
    function setTitle(newTitle) { title = newTitle }
}

// Person.qml
import QtQuick 2.0
Displayable {
    property string title
    property string firstName
    property string lastName

    function fullName()  { return title + " " + firstName + " " + lastName }
}

Ici, le nom title est donné à la fois à l'en-tête du texte de sortie de Displayable et au titre honorifique de l'objet Person.

Une propriété surchargée est résolue en fonction de la portée dans laquelle elle est référencée. Dans la portée du composant Person, ou à partir d'une portée externe qui fait référence à une instance du composant Person, title se résout à la propriété déclarée dans Person.qml. La fonction fullName fera référence à la propriété title déclarée dans Person.

À l'intérieur du composant Displayable, cependant, title fait référence à la propriété déclarée dans Displayable.qml. Les fonctions getTitle() et setTitle(), ainsi que la liaison pour la propriété text de l'objet Text feront toutes référence à la propriété title déclarée dans le composant Displayable.

Bien qu'elles portent le même nom, ces deux propriétés sont entièrement distinctes. Un gestionnaire de signal onChanged pour l'une des propriétés ne sera pas déclenché par une modification de l'autre propriété portant le même nom. Un alias de l'une ou l'autre propriété fera référence à l'une ou l'autre, mais pas aux deux.

Objet global JavaScript

QML interdit les noms de type, d'identifiant et de propriété qui entrent en conflit avec les propriétés de l'objet global afin d'éviter toute confusion. Les programmeurs peuvent être sûrs que Math.min(10, 9) fonctionnera toujours comme prévu !

Voir l'environnement hôte JavaScript pour plus d'informations.

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