Bereich und Namensauflösung

QML-Eigenschaftsbindungen, Inline-Funktionen und importierte JavaScript-Dateien werden alle in einem JavaScript-Bereich ausgeführt. Der Geltungsbereich steuert, auf welche Variablen ein Ausdruck zugreifen kann und welche Variable Vorrang hat, wenn zwei oder mehr Namen miteinander in Konflikt stehen.

Da der in JavaScript eingebaute Gültigkeitsbereich-Mechanismus sehr einfach ist, wurde er in QML erweitert, damit er besser zu den QML-Spracherweiterungen passt.

JavaScript-Bereich

Die QML-Bereichserweiterungen greifen nicht in das natürliche Scoping von JavaScript ein. JavaScript-Programmierer können ihr vorhandenes Wissen wiederverwenden, wenn sie Funktionen, Property-Bindings oder importierte JavaScript-Dateien in QML programmieren.

Im folgenden Beispiel fügt die Methode addConstant() dem übergebenen Parameter 13 hinzu, so wie es der Programmierer erwarten würde, unabhängig vom Wert der Eigenschaften a und b des QML-Objekts.

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

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

Dass QML die normalen Scoping-Regeln von JavaScript respektiert, gilt sogar für Bindungen. Diese abscheuliche Bindung weist der Eigenschaft a des QML-Objekts den Wert 12 zu.

QtObject {
    property int a

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

Jeder JavaScript-Ausdruck, jede Funktion oder Datei in QML hat sein eigenes, eindeutiges Variablenobjekt. Lokale Variablen, die in einem Objekt deklariert sind, werden niemals mit lokalen Variablen in Konflikt geraten, die in einem anderen deklariert sind.

Typennamen und importierte JavaScript-Dateien

QML-Dokumente enthalten Importanweisungen, die die für das Dokument sichtbaren Typnamen und JavaScript-Dateien definieren. Zusätzlich zu ihrer Verwendung in der QML-Deklaration selbst werden Typnamen von JavaScript-Code beim Zugriff auf angehängte Eigenschaften und Aufzählungswerte verwendet.

Die Auswirkung eines Imports gilt für jede Eigenschaftsbindung und jede JavaScript-Funktion im QML-Dokument, auch für die in verschachtelten Inline-Komponenten. Das folgende Beispiel zeigt eine einfache QML-Datei, die auf einige Aufzählungswerte zugreift und eine importierte JavaScript-Funktion aufruft.

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

Binding Scope Objekt

Ein Objekt, das eine Eigenschaftsbindung hat, wird als Scope-Objekt der Bindung bezeichnet. Im folgenden Beispiel ist das Item -Objekt das Scope-Objekt der Bindung.

Item {
    anchors.left: parent.left
}

Bindungen haben ohne Einschränkung Zugriff auf die Eigenschaften des Bereichsobjekts. Im vorherigen Beispiel greift die Bindung direkt auf die Eigenschaft parent von Item zu, ohne dass ein Objektpräfix erforderlich ist. QML führt einen stärker strukturierten, objektorientierten Ansatz für JavaScript ein und erfordert daher nicht die Verwendung der JavaScript-Eigenschaft this.

Beim Zugriff auf angehängte Eigenschaften aus Bindungen ist aufgrund ihrer Interaktion mit dem Scope-Objekt Vorsicht geboten. Konzeptionell existieren angehängte Eigenschaften auf allen Objekten, auch wenn sie sich nur auf eine Teilmenge von ihnen auswirken. Folglich werden unqualifizierte angehängte Eigenschaften immer zu einer angehängten Eigenschaft des Bereichsobjekts aufgelöst, was nicht immer die Absicht des Programmierers ist.

Zum Beispiel fügt der Typ PathView seinen Delegierten interpolierte Werteigenschaften zu, abhängig von ihrer Position im Pfad. Da PathView diese Eigenschaften sinnvollerweise nur an das Stammobjekt im Delegaten anhängt, muss jedes Unterobjekt, das auf sie zugreift, das Stammobjekt explizit qualifizieren, wie unten gezeigt.

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

Wenn das Objekt Image das Präfix root weglassen würde, würde es versehentlich auf die nicht gesetzte PathView.scale angehängte Eigenschaft auf sich selbst zugreifen.

Komponentenumfang

Jede QML-Komponente in einem QML-Dokument definiert einen logischen Bereich. Jedes Dokument hat mindestens eine Wurzelkomponente, kann aber auch andere Inline-Unterkomponenten haben. Der Komponentenbereich ist die Vereinigung der Objekt-IDs innerhalb der Komponente und der Eigenschaften des Wurzelobjekts der Komponente.

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
    }
}

Das obige Beispiel zeigt eine einfache QML-Komponente, die oben einen Rich-Text-Titelstring und unten eine kleinere Kopie desselben Textes anzeigt. Der erste Typ Text greift bei der Bildung des anzuzeigenden Textes direkt auf die Eigenschaft title der Komponente zu. Die Tatsache, dass die Eigenschaften des Root-Typs direkt zugänglich sind, macht es trivial, Daten in der gesamten Komponente zu verteilen.

Der zweite Typ Text verwendet eine ID, um direkt auf den Text des ersten Typs zuzugreifen. IDs werden vom QML-Programmierer explizit angegeben, so dass sie immer Vorrang vor anderen Eigenschaftsnamen haben (mit Ausnahme derjenigen im JavaScript-Scope). In dem unwahrscheinlichen Fall, dass das Scope-Objekt der Bindung im vorherigen Beispiel eine titletype -Eigenschaft hätte, hätte die titletype id immer noch Vorrang.

Komponenteninstanz-Hierarchie

In QML verbinden Komponenteninstanzen ihre Komponenten-Scopes miteinander und bilden so eine Scope-Hierarchie. Komponenteninstanzen können direkt auf die Komponenten-Scopes ihrer Vorgänger zugreifen.

Am einfachsten lässt sich dies anhand von Inline-Subkomponenten demonstrieren, deren Komponenten-Scopes implizit als Kinder der äußeren Komponente skaliert werden.

Item {
    property color defaultColor: "blue"

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

Die Komponenteninstanzhierarchie erlaubt Instanzen der delegierten Komponente den Zugriff auf die defaultColor Eigenschaft des Item Typs. Hätte die delegierte Komponente eine Eigenschaft namens defaultColor, hätte diese natürlich Vorrang gehabt.

Die Komponenteninstanzbereichshierarchie erstreckt sich auch auf Komponenten außerhalb der Zeile. Im folgenden Beispiel erstellt die Komponente TitlePage.qml zwei Instanzen von TitleText. Obwohl sich der Typ TitleText in einer separaten Datei befindet, hat er dennoch Zugriff auf die Eigenschaft title, wenn er von TitlePage aus verwendet wird. QML ist eine dynamisch skalierende Sprache - je nachdem, wo sie verwendet wird, kann die Eigenschaft title anders aufgelöst werden.

// 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
}

Dynamisches Scoping ist sehr mächtig, muss aber mit Bedacht eingesetzt werden, um zu verhindern, dass das Verhalten von QML-Code schwer vorhersehbar wird. Im Allgemeinen sollte es nur in Fällen verwendet werden, in denen die beiden Komponenten bereits auf andere Weise eng gekoppelt sind. Bei der Entwicklung von wiederverwendbaren Komponenten ist es vorzuziehen, Eigenschaftsschnittstellen wie diese zu verwenden:

// 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
}

Überschriebene Eigenschaften

QML erlaubt es, dass Eigenschaftsnamen, die in einer Objektdeklaration definiert sind, durch Eigenschaften überschrieben werden, die in einer anderen Objektdeklaration deklariert sind, die die erste erweitert. Ein Beispiel:

// 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 }
}

Hier wird der Name title sowohl für die Überschrift des Ausgabetextes für Displayable als auch für den Ehrentitel des Objekts Person verwendet.

Eine überschriebene Eigenschaft wird entsprechend dem Bereich, in dem sie referenziert wird, aufgelöst. Innerhalb des Bereichs der Komponente Person oder von einem externen Bereich, der sich auf eine Instanz der Komponente Person bezieht, löst title die in Person.qml deklarierte Eigenschaft auf. Die Funktion fullName verweist auf die innerhalb von Person deklarierte Eigenschaft title.

Innerhalb der Displayable-Komponente verweist title jedoch auf die in Displayable.qml deklarierte Eigenschaft. Die Funktionen getTitle() und setTitle() sowie die Bindung für die Eigenschaft text des Text-Objekts beziehen sich alle auf die in der Komponente Displayable deklarierte Eigenschaft title.

Obwohl sie denselben Namen haben, sind die beiden Eigenschaften völlig getrennt. Ein onChanged-Signalhandler für eine der Eigenschaften wird nicht durch eine Änderung der anderen Eigenschaft mit demselben Namen ausgelöst. Ein Alias für eine der beiden Eigenschaften verweist auf die eine oder die andere, aber nicht auf beide.

Globales JavaScript-Objekt

QML verbietet Typ-, Id- und Eigenschaftsnamen, die mit den Eigenschaften des globalen Objekts in Konflikt stehen, um Verwechslungen zu vermeiden. Programmierer können sich darauf verlassen, dass Math.min(10, 9) immer wie erwartet funktioniert!

Weitere Informationen finden Sie unter JavaScript-Host-Umgebung.

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