Portée et résolution des noms
Les liaisons de propriétés QML, les fonctions inline et les fichiers JavaScript importés s’exécutent tous dans une portée JavaScript. La portée détermine les variables auxquelles une expression peut accéder, ainsi que la variable qui prévaut en cas de conflit entre deux noms ou plus.
Le mécanisme de portée intégré à JavaScript étant très simple, QML l'améliore afin qu’il s’adapte plus naturellement aux extensions du langage QML.
Portée 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 dans QML.
Dans l’exemple suivant, la méthode ` addConstant() ` ajoutera 13 au paramètre passé, exactement 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 même aux liaisons. Cette liaison, véritable abomination, attribuera la valeur 12 à la propriété ` a ` de l’objet QML.
Chaque expression, fonction ou fichier JavaScript dans QML dispose de son propre objet variable unique. Les variables locales déclarées dans l’un n’entreront jamais en conflit avec celles déclarées dans un autre.
Noms de types et fichiers JavaScript importés
Les documents QML contiennent des instructions d’importation qui définissent les noms de types et les fichiers JavaScript visibles par le document. Outre leur utilisation dans la déclaration QML elle-même, les noms de types sont utilisés par le code JavaScript lors de l’accès aux propriétés associées et aux valeurs d’énumération.
L’effet d’une importation s’applique à chaque liaison de propriété et à chaque fonction JavaScript du document QML, même celles situées dans des composants inline imbriqués. L’exemple suivant montre un fichier QML simple 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 de portée de liaison
Un objet doté d’une liaison de propriété est appelé « objet de portée » de cette 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 de portée sans qualification. Dans l’exemple précédent, la liaison accède directement à la propriété ` parent ` de l’objet ` Item`, sans avoir besoin d’un préfixe d’objet. Le QML introduit une approche plus structurée et orientée objet du JavaScript et, par conséquent, ne nécessite pas l’utilisation de la propriété JavaScript ` this `.
Il convient de faire preuve de prudence lors de l’accès aux propriétés associées à partir de liaisons en raison de leur interaction avec l’objet de portée. Conceptuellement, les propriétés associé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 associées non qualifiées se résoudront toujours en une propriété associée à l’objet de portée, ce qui n’est pas toujours l’intention du programmeur.
Par exemple, le type ` PathView ` associe des propriétés de valeur interpolées à ses délégués en fonction de leur position dans le chemin. Comme ` PathView ` n’associe de manière significative 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 illustré ci-dessous.
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 comporte au moins un composant racine, mais peut également contenir d’autres sous-composants en ligne. La portée du composant correspond à l’union des identifiants d’objets au sein du composant et des propriétés de l’objet racine de ce 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 texte enrichi en haut, et une version plus petite du même texte en bas. Le premier type « Text » accède directement à la propriété « title » du composant lors de la formation du texte à afficher. Le fait que les propriétés du type racine soient directement accessibles facilite grandement la distribution des données à travers le composant.
Le deuxième type d’ Text utilise un identifiant pour accéder directement au texte du premier. Les identifiants sont spécifiés explicitement par le programmeur QML ; ils 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 de portée de la liaison disposerait d’une propriété « titletype » dans l’exemple précédent, l’identifiant « titletype » aurait tout de même la priorité.
Hiérarchie des instances de composants
En QML, les instances de composants relient entre elles leurs portées de composant pour former une hiérarchie de portées. Les instances de composants peuvent accéder directement aux portées de composant de leurs ancêtres.
La manière la plus simple d’illustrer cela consiste à utiliser des sous-composants en ligne dont les portées de composant sont implicitement définies comme des enfants du composant externe.
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 ` de type ` Item `. Bien sûr, si le composant délégué avait disposé d’une propriété nommée ` defaultColor `, celle-ci aurait eu la priorité.
La hiérarchie des portées d’instances de composants s’étend également aux composants hors ligne. Dans l’exemple suivant, le composant ` TitlePage.qml ` crée deux instances de ` TitleText `. Même si le type ` TitleText ` se trouve dans un fichier distinct, il a tout de même accès à la propriété ` title ` lorsqu’il est utilisé depuis l’intérieur de ` TitlePage`. QML est un langage à portée dynamique : selon l’endroit où il est utilisé, la propriété ` title ` peut se résoudre 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
}La portée dynamique est très puissante, mais elle doit être utilisée avec prudence pour éviter que le comportement du code QML ne devienne difficile à prévoir. En général, elle ne devrait être utilisée que dans les cas où les deux composants sont déjà étroitement couplés d’une autre manière. Lors de la création de composants réutilisables, il est préférable d’utiliser des interfaces de propriétés, 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’ id de l’objet racine depuis d’autres composants QML
Évitez d’accéder à l’ id d’un objet racine depuis l’extérieur du fichier QML où il est défini. Les valeurs d’ id ne sont valides qu’au sein du même document, et le fait de s’y référer depuis 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 tout de même car ` CustomItem ` est instancié dans un contexte où ` root ` existe, ce qui est autorisé par les règles de portée dynamique de QML. Cependant, cela crée une dépendance implicite vis-à-vis de la portée externe, 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 schéma 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 attendu, ce qui entraîne un comportement inattendu.
Pour rendre les composants fiables et réutilisables, accédez à l’état externe uniquement via des propriétés explicites, des alias de propriétés ou des signaux. Évitez de vous appuyer sur des valeurs d’ id s de la portée externe.
L’exemple suivant remplace la portée 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 un 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 à l’ id internalCounter depuis un autre fichier QML provoque une « ReferenceError » (erreur de portée), car une id est locale au document et ne peut pas être accessible en dehors du fichier QML dans lequel elle est déclarée.
Si un objet interne doit exposer un état ou un comportement, exposez-le explicitement via des propriétés, des alias de propriétés ou des signaux.
L’exemple suivant expose l’état interne via une API de composant explicite au lieu de s’appuyer sur un accès direct à une id locale au document.
// 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 favorise une meilleure évolutivité et testabilité.
Propriétés redéfinies
QML permet de redéfinir les noms de propriétés définis dans une déclaration d’objet par des propriétés déclarées dans une autre déclaration d’objet qui étend la première. Par 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 attribué à la fois à l’en-tête du texte de sortie pour Displayable et au titre honorifique de l’objet Person.
Une propriété redéfinie est résolue en fonction de la portée dans laquelle elle est référencée. À l’intérieur de la portée du composant Person, ou depuis une portée externe faisant référence à une instance du composant Person, « title » renvoie à 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, en revanche, title fait référence à la propriété déclarée dans Displayable.qml. Les fonctions getTitle() et setTitle(), ainsi que la liaison de 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 totalement distinctes. Un gestionnaire de signal onChanged associé à 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 vers l’une ou l’autre de ces propriétés fera référence à l’une ou à l’autre, mais pas aux deux.
Objet global JavaScript
QML interdit les noms de types, d’identifiants et de propriétés qui entrent en conflit avec les propriétés de l’objet global afin d’éviter toute confusion. Les programmeurs peuvent ainsi être assurés que ` Math.min(10, 9) ` fonctionnera toujours comme prévu !
Voir 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.