QML-Objektattribute
Jeder QML-Objekttyp verfügt über eine definierte Menge an Attributen. Jede Instanz eines Objekttyps wird mit der Menge an Attributen erstellt, die für diesen Objekttyp definiert wurden. Es gibt verschiedene Arten von Attributen, die angegeben werden können und die im Folgenden beschrieben werden.
Attribute in Objektdeklarationen
Eine Objektdeklaration in einem QML-Dokument definiert einen neuen Typ. Sie deklariert außerdem eine Objekthierarchie, die instanziiert wird, sobald eine Instanz dieses neu definierten Typs erstellt wird.
Die folgenden Attributtypen stehen für QML-Objekttypen zur Verfügung:
- das „id “-Attribut
- Eigenschaftsattribute
- Signal-Attribute
- Signal-Handler-Attribute
- Methodenattribute
- zugeordnete Eigenschaften und zugeordnete Signal-Handler-Attribute
- Aufzählungsattribute
Diese Attribute werden im Folgenden ausführlich erläutert.
Das id -Attribut
Ein QML-Element kann höchstens ein „id“-Attribut besitzen. Dieses Attribut wird von der Sprache selbst bereitgestellt und kann von keinem QML-Objekttyp neu definiert oder überschrieben werden.
Dem „id“-Attribut einer Objektinstanz kann ein Wert zugewiesen werden, damit dieses Objekt von anderen Objekten identifiziert und referenziert werden kann. Diese „ id “ muss mit einem Kleinbuchstaben oder einem Unterstrich beginnen und darf keine anderen Zeichen als Buchstaben, Ziffern und Unterstriche enthalten. Sie darf zudem kein JavaScript-Schlüsselwort sein. Eine Liste solcher Schlüsselwörter finden Sie in der ECMAScript-Sprachspezifikation.
Wenn Sie in QML einen Namen verwenden, der als JavaScript-Bezeichner ungeeignet ist, wie beispielsweise „as“, können Sie in JavaScript nicht auf das identifizierte Objekt verweisen, wodurch die ID weitgehend nutzlos wird. Sie können jedoch weiterhin „ QQmlContext “ aus C++ verwenden, um mit solchen IDszu interagieren.
Nachfolgend sind ein „ TextInput “-Objekt und ein „ Text “-Objekt dargestellt. Der Wert von „ id “ des „ TextInput “-Objekts ist auf „myTextInput“ gesetzt. Das „ Text “-Objekt setzt seine Eigenschaft „ text “ so, dass sie denselben Wert wie die Eigenschaft „ text “ des „ TextInput “ hat, indem es auf „ myTextInput.text “ verweist. Nun zeigen beide Elemente denselben Text an:
import QtQuick
Column {
width: 200; height: 200
TextInput { id: myTextInput; text: "Hello World" }
Text { text: myTextInput.text }
}Ein Objekt kann von überall innerhalb des QML-Kontexts, in dem es erstellt wurde, über seine ` id ` referenziert werden. Daher muss ein ` id `-Wert innerhalb seines Kontexts immer eindeutig sein. Weitere Informationen finden Sie unter „Gültigkeitsbereich und Namensauflösung “.
Der Kontext wird über die „ QQmlContext “-Hierarchie auch für C++ verfügbar gemacht. Sie können beispielsweise den Kontext eines bestimmten Objekts über die Funktion „ qmlContext “ abrufen und nach anderen Objekten im selben Kontext fragen:
QObject *textInput = qmlContext(theColumn)->objectForName("myTextInput");Sobald eine Objektinstanz erstellt wurde, kann der Wert ihres `id` -Attributs nicht mehr geändert werden. Auch wenn es wie eine gewöhnliche Eigenschaft aussieht, ist das ` id `-Attribut kein gewöhnliches ` property `-Attribut, und es gelten besondere Regeln; so ist es beispielsweise nicht möglich, im obigen Beispiel auf ` myTextInput.id ` zuzugreifen.
Eigenschaftsattribute
Eine Eigenschaft ist ein Attribut eines Objekts, dem ein statischer Wert zugewiesen oder das an einen dynamischen Ausdruck gebunden werden kann. Der Wert einer Eigenschaft kann von anderen Objekten gelesen werden. Im Allgemeinen kann er auch von einem anderen Objekt geändert werden, es sei denn, ein bestimmter QML-Typ hat dies für eine bestimmte Eigenschaft ausdrücklich untersagt.
Definition von Eigenschaftsattributen
Eine Eigenschaft kann für einen Typ in C++ definiert werden, indem ein „ Q_PROPERTY “ einer Klasse registriert wird, das anschließend im QML-Typsystem registriert wird. Alternativ kann eine benutzerdefinierte Eigenschaft eines Objekttyps in einer Objektdeklaration in einem QML-Dokument mit der folgenden Syntax definiert werden:
[default] [virtual] [override] [final] [required] [readonly] property <propertyType> <propertyName>Auf diese Weise kann eine Objektdeklaration einen bestimmten Wert für externe Objekte zugänglich machen oder einen internen Zustand einfacher verwalten.
Eigenschaftsnamen müssen mit einem Kleinbuchstaben beginnen und dürfen nur Buchstaben, Ziffern und Unterstriche enthalten. In JavaScript reservierte Schlüsselwörter sind keine gültigen Eigenschaftsnamen. Die Schlüsselwörter „ default “, „ required “, „ readonly “, „ virtual “, „ override “ und „ final “ sind optional und modifizieren die Semantik der deklarierten Eigenschaft. Weitere Informationen zu deren jeweiliger Bedeutung finden Sie in den folgenden Abschnitten zu Standard-Eigenschaften, erforderlichen Eigenschaften, schreibgeschützten Eigenschaften und der Semantik von Überschreibungen.
Durch die Deklaration einer benutzerdefinierten Eigenschaft wird implizit ein Signal für Wertänderungen dieser Eigenschaft sowie ein zugehöriger Signal-Handler namens on<PropertyName>Changed erstellt, wobei <PropertyName> der Name der Eigenschaft ist, dessen erster Buchstabe großgeschrieben wird.
Die folgende Objektdeklaration definiert beispielsweise einen neuen Typ, der vom Basistyp „Rectangle“ abgeleitet ist. Er verfügt über zwei neue Eigenschaften, wobei für eine dieser neuen Eigenschaften ein Signal-Handler implementiert ist:
Rectangle {
property color previousColor
property color nextColor
onNextColorChanged: console.log("The next color will be: " + nextColor.toString())
}Gültige Typen in benutzerdefinierten Eigenschaftsdefinitionen
Jeder der QML-Werttypen kann als benutzerdefinierter Eigenschaftstyp verwendet werden. Beispielsweise sind dies alles gültige Eigenschaftsdeklarationen:
(Aufzählungswerte sind einfach ganzzahlige Werte und können stattdessen mit dem Typ ` int ` referenziert werden.)
Einige Werttypen werden vom Modul „ QtQuick “ bereitgestellt und können daher nur dann als Eigenschaftstypen verwendet werden, wenn das Modul importiert wurde. Weitere Informationen finden Sie in der Dokumentation zu den QML-Werttypen.
Beachten Sie, dass der Werttyp „ var “ ein generischer Platzhaltertyp ist, der jede Art von Wert aufnehmen kann, einschließlich Listen und Objekten:
property var someNumber: 1.5
property var someString: "abc"
property var someBool: true
property var someList: [1, 2, "three", "four"]
property var someObject: Rectangle { width: 100; height: 100; color: "red" }Darüber hinaus kann jeder QML-Objekttyp als Eigenschaftstyp verwendet werden. Zum Beispiel:
property Item someItem
property Rectangle someRectangleDies gilt auch für benutzerdefinierte QML-Typen. Wenn ein QML-Typ in einer Datei namens „ ColorfulButton.qml “ (in einem Verzeichnis, das anschließend vom Client importiert wurde) definiert wurde, wäre auch eine Eigenschaft vom Typ „ ColorfulButton “ gültig.
Zuweisung von Werten an Eigenschaftsattribute
Der Wert einer Eigenschaft einer Objektinstanz kann auf zwei verschiedene Arten festgelegt werden:
- eine Wertzuweisung bei der Initialisierung
- eine imperative Wertzuweisung
In beiden Fällen kann der Wert entweder ein statischer Wert oder der Wert eines Bindungsausdrucks sein.
Wertzuweisung bei der Initialisierung
Die Syntax für die Zuweisung eines Werts zu einer Eigenschaft bei der Initialisierung lautet:
<propertyName> : <value>Eine Wertzuweisung bei der Initialisierung kann auf Wunsch mit einer Eigenschaftsdefinition in einer Objektdeklaration kombiniert werden. In diesem Fall lautet die Syntax der Eigenschaftsdefinition:
[default] property <propertyType> <propertyName> : <value>Es folgt ein Beispiel für die Initialisierung eines Eigenschaftswerts:
import QtQuick
Rectangle {
color: "red"
property color nextColor: "blue" // combined property declaration and initialization
}Imperative Wertzuweisung
Bei einer imperativen Wertzuweisung wird einer Eigenschaft aus imperativem JavaScript-Code ein Wert (entweder ein statischer Wert oder ein Bindungsausdruck) zugewiesen. Die Syntax einer imperativen Wertzuweisung besteht lediglich aus dem JavaScript-Zuweisungsoperator, wie unten gezeigt:
[<objectId>.]<propertyName> = valueEs folgt ein Beispiel für eine imperative Wertzuweisung:
import QtQuick
Rectangle {
id: rect
Component.onCompleted: {
rect.color = "red"
}
}Statische Werte und Werte von Bindungsausdrücken
Wie bereits erwähnt, gibt es zwei Arten von Werten, die einer Eigenschaft zugewiesen werden können: statische Werte und Werte von Bindungsausdrücken. Letztere werden auch als Eigenschaftsbindungen bezeichnet.
| Art | Semantik |
|---|---|
| Statischer Wert | Ein konstanter Wert, der nicht von anderen Eigenschaften abhängt. |
| Bindungsausdruck | Ein JavaScript-Ausdruck, der die Beziehung einer Eigenschaft zu anderen Eigenschaften beschreibt. Die Variablen in diesem Ausdruck werden als Abhängigkeiten der Eigenschaft bezeichnet. Die QML-Engine sorgt für die Einhaltung der Beziehung zwischen einer Eigenschaft und ihren Abhängigkeiten. Wenn sich der Wert einer der Abhängigkeiten ändert, wertet die QML-Engine den Bindungsausdruck automatisch neu aus und weist der Eigenschaft das neue Ergebnis zu. |
Hier ist ein Beispiel, das beide Arten der Zuweisung von Werten zu Eigenschaften veranschaulicht:
import QtQuick
Rectangle {
// both of these are static value assignments on initialization
width: 400
height: 200
Rectangle {
// both of these are binding expression value assignments on initialization
width: parent.width / 2
height: parent.height
}
}Hinweis: Um einen Bindungsausdruck imperativ zuzuweisen, muss der Bindungsausdruck in einer Funktion enthalten sein, die an ` Qt.binding()` übergeben wird, und anschließend muss der von `Qt.binding()` zurückgegebene Wert der Eigenschaft zugewiesen werden. Im Gegensatz dazu darf `Qt.binding()` nicht verwendet werden, wenn ein Bindungsausdruck bei der Initialisierung zugewiesen wird. Weitere Informationen finden Sie unter „Eigenschaftsbindung “.
Typsicherheit
Eigenschaften sind typsicher. Einer Eigenschaft kann nur ein Wert zugewiesen werden, der mit dem Eigenschaftstyp übereinstimmt.
Wenn eine Eigenschaft beispielsweise vom Typ `int` ist und Sie versuchen, ihr eine Zeichenkette zuzuweisen, wird ein Fehler ausgegeben:
property int volume: "four" // generates an error; the property's object will not be loadedEbenso wird, wenn einer Eigenschaft zur Laufzeit ein Wert des falschen Typs zugewiesen wird, der neue Wert nicht zugewiesen und es wird ein Fehler ausgelöst.
Einige Eigenschaftstypen verfügen über keine natürliche Wertdarstellung; für diese Eigenschaftstypen führt die QML-Engine automatisch eine Konvertierung von Zeichenketten in typisierte Werte durch. So kannst du beispielsweise, obwohl Eigenschaften vom Typ „ color “ Farben und keine Zeichenketten speichern, der Farbeigenschaft die Zeichenkette „ "red" “ zuweisen, ohne dass ein Fehler gemeldet wird.
Eine Liste der standardmäßig unterstützten Eigenschaftstypen finden Sie unter „QML-Werttypen “. Darüber hinaus kann jeder verfügbare QML-Objekttyp auch als Eigenschaftstyp verwendet werden.
Spezielle Eigenschaftstypen
Attribute von Objektlisten-Eigenschaften
Einer Eigenschaft vom Typ „ list “ kann eine Liste von Werten vom Typ „QML-Objekt“ zugewiesen werden. Die Syntax zur Definition eines Objektlistenwerts besteht aus einer durch Kommas getrennten Liste, die von eckigen Klammern umschlossen ist:
[ <item 1>, <item 2>, ... ]Beispielsweise verfügt der Typ „ Item “ über eine Eigenschaft „ states “, die eine Liste von Objekten vom Typ „ State “ enthält. Der folgende Code initialisiert den Wert dieser Eigenschaft mit einer Liste aus drei „ State “-Objekten:
import QtQuick
Item {
states: [
State { name: "loading" },
State { name: "running" },
State { name: "stopped" }
]
}Wenn die Liste nur ein Element enthält, können die eckigen Klammern weggelassen werden:
Eine Eigenschaft vom Typ „ list “ kann in einer Objektdeklaration mit der folgenden Syntax angegeben werden:
[default] property list<<ObjectType>> propertyNameUnd wie bei anderen Eigenschaftsdeklarationen kann die Initialisierung einer Eigenschaft mit der Eigenschaftsdeklaration unter Verwendung der folgenden Syntax kombiniert werden:
[default] property list<<ObjectType>> propertyName: <value>Es folgt ein Beispiel für die Deklaration einer Listen-Eigenschaft:
import QtQuick
Rectangle {
// declaration without initialization
property list<Rectangle> siblingRects
// declaration with initialization
property list<Rectangle> childRects: [
Rectangle { color: "red" },
Rectangle { color: "blue"}
]
}Wenn Sie eine Eigenschaft deklarieren möchten, um eine Liste von Werten zu speichern, bei denen es sich nicht unbedingt um Werte vom Typ „QML-Objekt“ handeln muss, sollten Sie stattdessen eine „ var “-Eigenschaft deklarieren.
Gruppierte Eigenschaften
In einigen Fällen enthalten Eigenschaften eine logische Gruppe von Untereigenschaftsattributen. Diese Untereigenschaftsattribute können entweder mithilfe der Punktnotation oder der Gruppennotation zugewiesen werden.
Beispielsweise verfügt der Typ „ Text “ über eine Eigenschaft „ font “. Im folgenden Beispiel initialisiert das erste „ Text “-Objekt seine „ font “-Werte mithilfe der Punktnotation, während das zweite die Gruppennotation verwendet:
Text {
//dot notation
font.pixelSize: 12
font.bold: true
}
Text {
//group notation
font { pixelSize: 12; bold: true }
}Die Syntax für gruppierte Eigenschaften steht für jede Eigenschaft zur Verfügung, deren Typ eigene Untereigenschaften besitzt. Es handelt sich um eine Notation, nicht um eine separate Art von Eigenschaft: Ob die Eigenschaft einen Werttyp wie „ font “ oder einen Objekttyp enthält, macht für die Syntax keinen Unterschied.
Der Typ der Eigenschaft hat jedoch Einfluss darauf, was die Engine tun muss:
- Wenn die Eigenschaft einen Werttyp enthält, liest die Engine den Wert, ändert ihn und schreibt ihn zurück. Die Eigenschaft muss daher beschreibbar sein.
- Wenn die Eigenschaft einen Objekttyp enthält, werden die Zuweisungen in das Objekt geschrieben, das die Eigenschaft derzeit enthält. Dieses Objekt darf zum Zeitpunkt der Zuweisungen nicht null sein. Die Eigenschaft selbst kann schreibgeschützt oder beschreibbar sein. Die Festlegung als schreibgeschützt verhindert, dass QML-Code das Objekt ersetzt, zu dem die Untereigenschaften gehören, wodurch Unklarheiten darüber vermieden werden, auf welches Objekt sich die gruppierten Eigenschaften beziehen. Dies ist im Allgemeinen empfehlenswert.
Die Namen von Untereigenschaften werden anhand des deklarierten Typs der Eigenschaft aufgelöst, nicht anhand des Typs des Objekts, das sie zur Laufzeit enthält. Du kannst außerdem nicht beide Formen für dieselbe Eigenschaft in derselben Objektdefinition verwenden: Entweder weist du der Eigenschaft ein Objekt zu oder du weist ihren Untereigenschaften Werte zu.
Eigenschaftsaliase
Eigenschaftsaliase sind Eigenschaften, die eine Referenz auf eine andere Eigenschaft enthalten. Im Gegensatz zu einer gewöhnlichen Eigenschaftsdefinition, bei der ein neuer, eindeutiger Speicherplatz für die Eigenschaft zugewiesen wird, verbindet ein Eigenschaftsalias die neu deklarierte Eigenschaft (die sogenannte Aliasing-Eigenschaft) als direkte Referenz mit einer bestehenden Eigenschaft (der aliasierten Eigenschaft).
Eine Eigenschaftsalias-Deklaration sieht wie eine gewöhnliche Eigenschaftsdefinition aus, mit dem Unterschied, dass anstelle eines Eigenschaftstyps das Schlüsselwort ` alias ` erforderlich ist und die rechte Seite der Eigenschaftsdeklaration eine gültige Aliasreferenz sein muss:
[default] property alias <name>: <alias reference>Im Gegensatz zu einer gewöhnlichen Eigenschaft unterliegt ein Alias den folgenden Einschränkungen:
- Er kann sich nur auf ein Objekt oder die Eigenschaft eines Objekts beziehen, das sich im Geltungsbereich des Typs befindet, in dem der Alias deklariert ist.
- Er darf keine beliebigen JavaScript-Ausdrücke enthalten.
- Er darf nicht auf Objekte verweisen, die außerhalb des Gültigkeitsbereichs seines Typs deklariert sind.
- Die Alias-Referenz ist nicht optional, im Gegensatz zum optionalen Standardwert einer gewöhnlichen Eigenschaft; die Alias-Referenz muss bei der ersten Deklaration des Alias angegeben werden.
- Er darf nicht auf angehängte Eigenschaften verweisen.
- Er darf nicht auf Eigenschaften innerhalb einer Hierarchie mit einer Tiefe von 3 oder mehr verweisen. Der folgende Code funktioniert nicht:
property alias color: myItem.myRect.border.color Item { id: myItem property Rectangle myRect }Aliase auf Eigenschaften, die bis zu zwei Ebenen tief liegen, funktionieren jedoch.
property alias color: rectangle.border.color Rectangle { id: rectangle }
Beispielsweise ist unten ein Typ „ Button “ mit einer Eigenschaft „ buttonText “ als Alias aufgeführt, die mit dem Objekt „ text “ des untergeordneten Objekts „ Text “ verknüpft ist:
// Button.qml
import QtQuick
Rectangle {
property alias buttonText: textItem.text
width: 100; height: 30; color: "yellow"
Text { id: textItem }
}Der folgende Code würde ein ` Button ` mit einer definierten Textzeichenfolge für das untergeordnete ` Text `-Objekt erstellen:
Button { buttonText: "Click Me" }Hier führt eine Änderung an „ buttonText “ direkt zu einer Änderung des Werts von „textItem.text“; es wird nicht irgendein anderer Wert geändert, der dann „textItem.text“ aktualisiert. Wäre „ buttonText “ kein Alias, würde eine Änderung seines Werts den angezeigten Text tatsächlich überhaupt nicht verändern, da Eigenschaftsbindungen nicht bidirektional sind: Der Wert von „ buttonText “ hätte sich geändert, wenn „textItem.text“ geändert worden wäre, aber nicht umgekehrt.
Eigenschaftsaliase und Typen
Eigenschaftsaliase können keine expliziten Typangaben haben. Der Typ eines Eigenschaftsalias ist der deklarierte Typ der Eigenschaft oder des Objekts, auf das er verweist. Wenn Sie also einen Alias für ein Objekt erstellen, auf das über eine ID verwiesen wird und das zusätzliche, inline deklarierte Eigenschaften besitzt, sind diese zusätzlichen Eigenschaften über den Alias nicht zugänglich:
// MyItem.qml
Item {
property alias inner: innerItem
Item {
id: innerItem
property int extraProperty
}
}Sie können „ inner.extraProperty “ nicht von außerhalb dieser Komponente initialisieren, da „inner“ lediglich ein „ Item “ ist:
// main.qml
MyItem {
inner.extraProperty: 5 // fails
}Wenn Sie das „inner“-Objekt jedoch in eine separate Komponente mit einer eigenen .qml-Datei auslagern, können Sie stattdessen diese Komponente instanziieren und haben alle ihre Eigenschaften über den Alias zur Verfügung:
// MainItem.qml
Item {
// Now you can access inner.extraProperty, as inner is now an ExtraItem
property alias inner: innerItem
ExtraItem {
id: innerItem
}
}
// ExtraItem.qml
Item {
property int extraProperty
}Standard-Eigenschaften
Eine Objektdefinition kann eine einzige Standard-Eigenschaft haben. Wenn ein Objekt direkt in einem anderen Objekt verschachtelt ist, ohne dass eine Eigenschaft angegeben wird, wird es automatisch der Standard-Eigenschaft des umschließenden Objekts zugewiesen.
Durch die Deklaration einer Eigenschaft mit dem optionalen Schlüsselwort „ default “ wird diese als Standardeigenschaft gekennzeichnet. Nehmen wir beispielsweise an, es gibt eine Datei „Framer.qml“ mit der Standardeigenschaft „ focusItem “:
// Framer.qml
import QtQuick
Row {
default property Item focusItem
property Item leftItem: Rectangle {
width: 10
height: parent.height
color: "red"
}
property Item rightItem: Rectangle {
width: 10
height: parent.height
color: "blue"
}
children: [leftItem, focusItem, rightItem]
}Der Wert „ focusItem “ könnte in einer Objektdefinition für „ Framer “ wie folgt zugewiesen werden:
Framer {
Text { text: "Hello, world!" }
}Dies hat genau denselben Effekt wie Folgendes:
Framer {
focusItem: Text { text: "Hello, world!" }
}Da die Eigenschaft „ focusItem “ jedoch als Standard-Eigenschaft gekennzeichnet wurde, ist es nicht erforderlich, das Objekt „ Text “ dieser Eigenschaft explizit zuzuweisen.
Zwar kann eine Eigenschaft beliebigen Typs als „ default “-Eigenschaft markiert werden, doch ist es im Allgemeinen nur sinnvoll, Eigenschaften vom Typ „ var “, vom Objekttyp sowie deren jeweilige Sequenztypen zu markieren: Da der Standardeigenschaft nur Objektinstanzen zugewiesen werden, hat es in QML keinen Vorteil, beispielsweise eine String-Eigenschaft vom Typ „ default “ zu definieren.
Betrachten Sie den folgenden Typ „TextHolder“:
// TextHolder.qml
Item {
property default string mytext
}An sich ist das in Ordnung. Allerdings kann man „ mytext “ kein String-Literal zuweisen, ohne den Eigenschaftsnamen explizit anzugeben:
TextHolder {
/* The following would be a syntax error, and will not assign
to the mytext property:
"some text"
The line below is the only way to assign the value:
\1/
mytext: "some text"
}Sie werden feststellen, dass untergeordnete Objekte jedem auf „ Item “ basierenden Typ hinzugefügt werden können, ohne dass sie explizit der Eigenschaft „ children “ hinzugefügt werden müssen. Das liegt daran, dass die Standard-Eigenschaft von „ Item “ die Eigenschaft „ data “ ist und alle Elemente, die für ein „ Item “ zu dieser Liste hinzugefügt werden, automatisch auch zur Liste „ children “ dieses „ “ hinzugefügt werden.
Standard-Eigenschaften können nützlich sein, um die untergeordneten Elemente eines Elements neu zuzuordnen. Beispiel:
Durch Festlegen des Alias der Standard-Eigenschaft auf „ inner.children “ wird jedes Objekt, das als Kind des äußeren Elements zugewiesen wird, automatisch als Kind des inneren Elements neu zugewiesen.
Warnung: Die Festlegung der Werte für die Standard-Listen-Eigenschaft eines Elements kann implizit oder explizit erfolgen. Innerhalb der Definition eines einzelnen Elements dürfen diese beiden Methoden nicht gemischt werden, da dies zu einer undefinierten Reihenfolge der Elemente in der Liste führt.
Item {
// Use either implicit or explicit assignement to the default list property but not both!
Rectangle { width: 40 } // implicit
data: [ Rectangle { width: 100 } ] // explicit
}Überschreibungssemantik
Standardmäßig können Eigenschaften überschrieben werden: Sie deklarieren eine Eigenschaft in einem abgeleiteten QML-Typ neu, möglicherweise mit einem neuen Typ und neuen Attributen. Dies führt zu zwei Eigenschaften mit demselben Namen, von denen in einem bestimmten Kontext jeweils nur eine zugänglich ist. Dies ist selten beabsichtigt. Oft geschieht dies unbeabsichtigt, und meistens sind die Auswirkungen ziemlich verwirrend. Zudem ist das Überschatten schlecht für die Tooling-Unterstützung.
Um dem entgegenzuwirken, wurden die Schlüsselwörter „ virtual “, „ override “ und „ final “ sowie zusätzliche Warnungen und Fehlermeldungen eingeführt.
Weitere Details und eine umfassende Sammlung von Beispielen, einschließlich Warnungen und Fehlern, finden Sie auf der Seite „Property Shadowing and Override Semantics “.
Erforderliche Eigenschaften
Eine Objektdeklaration kann eine Eigenschaft mithilfe des Schlüsselworts „ required “ als erforderlich definieren. Die Syntax lautet
required property <propertyType> <propertyName>Wie der Name schon sagt, müssen erforderliche Eigenschaften beim Erstellen einer Instanz des Objekts gesetzt werden. Ein Verstoß gegen diese Regel führt dazu, dass QML-Anwendungen nicht starten, sofern dies statisch erkannt werden kann. Bei dynamisch instanziierten QML-Komponenten (beispielsweise über ` Qt.createComponent())` führt ein Verstoß gegen diese Regel zu einer Warnung und einem Rückgabewert von `null`.
Es ist möglich, eine bestehende Eigenschaft mit
required <propertyName>Das folgende Beispiel zeigt, wie man eine benutzerdefinierte „Rectangle“-Komponente erstellt, bei der die Eigenschaft „color“ immer angegeben werden muss.
// ColorRectangle.qml
Rectangle {
required color
}Hinweis: Du kannst einer erforderlichen Eigenschaft von QML aus keinen Anfangswert zuweisen, da dies der beabsichtigten Verwendung von erforderlichen Eigenschaften direkt zuwiderlaufen würde.
Erforderliche Eigenschaften spielen im Model-View-Delegate-Code eine besondere Rolle: Wenn der Delegate einer Ansicht erforderliche Eigenschaften hat, deren Namen mit den Rollennamen des Modells der Ansicht übereinstimmen, werden diese Eigenschaften mit den entsprechenden Werten des Modells initialisiert. Weitere Informationen finden Sie auf der Seite „Modelle und Ansichten“ unter Qt Quick.
Informationen zur Initialisierung von erforderlichen Eigenschaften aus C++ finden Sie unter „ QQmlComponent::createWithInitialProperties “, „ QQmlApplicationEngine::setInitialProperties “ und „ QQuickView::setInitialProperties “.
Schreibgeschützte Eigenschaften
In einer Objektdeklaration kann eine schreibgeschützte Eigenschaft mithilfe des Schlüsselworts „ readonly “ mit der folgenden Syntax definiert werden:
readonly property <propertyType> <propertyName> : <value>Schreibgeschützten Eigenschaften muss bei der Initialisierung ein statischer Wert oder ein Bindungsausdruck zugewiesen werden. Nachdem eine schreibgeschützte Eigenschaft initialisiert wurde, können Sie ihren statischen Wert oder Bindungsausdruck nicht mehr ändern.
Beispielsweise ist der Code im folgenden „ Component.onCompleted “-Block ungültig:
Item {
readonly property int someNumber: 10
Component.onCompleted: someNumber = 20 // TypeError: Cannot assign to read-only property
}Hinweis: Eine schreibgeschützte Eigenschaft kann nicht gleichzeitig eine Standard -Eigenschaft sein.
Eigenschaftsmodifikator-Objekte
Eigenschaften können mit Objekten zur Modifizierung von Eigenschaftswerten verknüpft sein. Die Syntax zur Deklaration einer Instanz eines Eigenschaftsmodifikatortyps, der einer bestimmten Eigenschaft zugeordnet ist, lautet wie folgt:
<PropertyModifierTypeName> on <propertyName> {
// attributes of the object instance
}Dies wird gemeinhin als „on“-Syntax bezeichnet.
Es ist wichtig zu beachten, dass es sich bei der obigen Syntax tatsächlich um eine Objektdeklaration handelt, die ein Objekt instanziiert, das auf eine bereits vorhandene Eigenschaft einwirkt.
Bestimmte Eigenschaftsmodifikator-Typen sind möglicherweise nur auf bestimmte Eigenschaftstypen anwendbar, dies wird jedoch von der Sprache nicht erzwungen. Beispielsweise animiert der Typ „ NumberAnimation “, der von „ QtQuick “ bereitgestellt wird, nur Eigenschaften vom numerischen Typ (wie „ int “ oder „ real “). Der Versuch, einen „ NumberAnimation “ mit einer nicht-numerischen Eigenschaft zu verwenden, führt zwar nicht zu einem Fehler, die nicht-numerische Eigenschaft wird jedoch nicht animiert. Das Verhalten eines Eigenschaftsmodifikatortyps bei der Zuordnung zu einem bestimmten Eigenschaftstyp wird durch dessen Implementierung definiert.
Signalattribute
Ein Signal ist eine Benachrichtigung eines Objekts, dass ein bestimmtes Ereignis eingetreten ist: zum Beispiel, dass sich eine Eigenschaft geändert hat, eine Animation gestartet oder gestoppt wurde oder dass ein Bild heruntergeladen wurde. Der Typ „ MouseArea “ verfügt beispielsweise über das Signal „ clicked “, das ausgelöst wird, wenn der Benutzer innerhalb des Mausbereichs klickt.
Ein Objekt kann über einen Signal-Handler benachrichtigt werden, sobald ein bestimmtes Signal ausgesendet wird. Ein Signal-Handler wird mit der Syntax `on<Signal> ` deklariert, wobei `<Signal> ` der Name des Signals ist und der erste Buchstabe großgeschrieben wird. Der Signal-Handler muss innerhalb der Definition des Objekts deklariert werden, das das Signal aussendet, und der Handler sollte den JavaScript-Codeblock enthalten, der ausgeführt werden soll, wenn der Signal-Handler aufgerufen wird.
Beispielsweise wird der folgende Signal-Handler „onClicked“ innerhalb der Definition des Objekts „ MouseArea “ deklariert und aufgerufen, wenn auf das Objekt „ MouseArea “ geklickt wird, wodurch eine Konsolenmeldung ausgegeben wird:
import QtQuick
Item {
width: 100; height: 100
MouseArea {
anchors.fill: parent
onClicked: {
console.log("Click!")
}
}
}Signalattribute definieren
Ein Signal kann für einen Typ in C++ definiert werden, indem ein „ Q_SIGNAL “ einer Klasse registriert wird, der anschließend im QML-Typsystem registriert wird. Alternativ kann ein benutzerdefiniertes Signal für einen Objekttyp in einer Objektdeklaration in einem QML-Dokument mit der folgenden Syntax definiert werden:
signal <signalName>[([<parameterName>: <parameterType>[, ...]])]Der Versuch, zwei Signale oder Methoden mit demselben Namen im selben Typblock zu deklarieren, führt zu einem Fehler. Ein neues Signal kann jedoch den Namen eines bereits vorhandenen Signals des Typs wiederverwenden. (Dies sollte mit Vorsicht geschehen, da das vorhandene Signal dadurch möglicherweise ausgeblendet wird und nicht mehr zugänglich ist.)
Hier sind drei Beispiele für Signaldeklarationen:
import QtQuick
Item {
signal clicked
signal hovered()
signal actionPerformed(action: string, actionResult: int)
}Sie können Signalparameter auch in der Syntax im Eigenschaftsstil angeben:
signal actionCanceled(string action)Um die Konsistenz mit Methodendeklarationen zu wahren, sollten Sie Typdeklarationen mit Doppelpunkten bevorzugen.
Wenn das Signal keine Parameter hat, sind die Klammern „()“ optional. Werden Parameter verwendet, müssen die Parametertypen deklariert werden, wie bei den Argumenten „ string “ und „ int “ für das oben genannte Signal „ actionPerformed “. Die zulässigen Parametertypen entsprechen denen, die unter „Definieren von Eigenschaftsattributen“ auf dieser Seite aufgeführt sind.
Um ein Signal auszulösen, rufen Sie es als Methode auf. Alle relevanten Signal-Handler werden aufgerufen, wenn das Signal ausgelöst wird, und die Handler können über die definierten Signal-Argumentnamen auf die jeweiligen Argumente zugreifen.
Signale bei Eigenschaftsänderungen
QML-Typen bieten außerdem integrierte Signale bei Eigenschaftsänderungen, die immer dann ausgelöst werden, wenn sich ein Eigenschaftswert ändert, wie zuvor im Abschnitt über Eigenschaftsattribute beschrieben. Weitere Informationen darüber, warum diese Signale nützlich sind und wie man sie verwendet, finden Sie im folgenden Abschnitt über Signal-Handler für Eigenschaftsänderungen.
Attribute von Signal-Handlern
Signal-Handler sind eine besondere Art von Methodenattributen, bei denen die Methodenimplementierung von der QML-Engine aufgerufen wird, sobald das zugehörige Signal ausgelöst wird. Das Hinzufügen eines Signals zu einer Objektdefinition in QML fügt der Objektdefinition automatisch einen zugehörigen Signal-Handler hinzu, der standardmäßig eine leere Implementierung aufweist. Clients können eine Implementierung bereitstellen, um die Programmlogik zu realisieren.
Betrachten Sie den folgenden Typ „ SquareButton “, dessen Definition in der Datei „ SquareButton.qml “ wie unten gezeigt bereitgestellt wird, mit den Signalen „ activated “ und „ deactivated “:
// SquareButton.qml
Rectangle {
id: root
signal activated(xPosition: real, yPosition: real)
signal deactivated
property int side: 100
width: side; height: side
MouseArea {
anchors.fill: parent
onReleased: root.deactivated()
onPressed: mouse => root.activated(mouse.x, mouse.y)
}
}Diese Signale könnten von beliebigen „ SquareButton “-Objekten in einer anderen QML-Datei im selben Verzeichnis empfangen werden, wobei die Implementierungen für die Signalhandler vom Client bereitgestellt werden:
// myapplication.qml
SquareButton {
onDeactivated: console.log("Deactivated!")
onActivated: (xPosition, yPosition) => {
console.log(`Activated at ${xPosition}, ${yPosition}`)
}
}Signal-Handler müssen ihre Parametertypen nicht deklarieren, da diese bereits durch das Signal festgelegt sind. Die oben gezeigte Pfeilfunktionssyntax unterstützt keine Typangaben.
Weitere Details zur Verwendung von Signalen finden Sie im Abschnitt „Signal- und Handler-Ereignissystem “.
Signal-Handler für Eigenschaftsänderungen
Signal-Handler für das Signal „Property Change“ haben die Syntax on<Property>Changed, wobei <Property> der Name der Eigenschaft ist, dessen erster Buchstabe großgeschrieben wird. Obwohl beispielsweise in der Typdokumentation zu „ TextInput “ kein Signal „ textChanged “ dokumentiert ist, steht dieses Signal implizit zur Verfügung, da „ TextInput “ über die Eigenschaft „ text “ verfügt. Daher ist es möglich, einen Signal-Handler „ onTextChanged “ zu schreiben, der bei jeder Änderung dieser Eigenschaft aufgerufen wird:
import QtQuick
TextInput {
text: "Change this!"
onTextChanged: console.log(`Text has changed to: ${text}`)
}Methodenattribute
Eine Methode eines Objekttyps ist eine Funktion, die aufgerufen werden kann, um eine Verarbeitung durchzuführen oder weitere Ereignisse auszulösen. Eine Methode kann mit einem Signal verknüpft werden, sodass sie automatisch aufgerufen wird, sobald das Signal ausgesendet wird. Weitere Details finden Sie unter „Signal- und Handler-Ereignissystem “.
Definition von Methodenattributen
Eine Methode kann für einen Typ in C++ definiert werden, indem eine Funktion einer Klasse markiert wird, die anschließend mit „ Q_INVOKABLE “ im QML-Typsystem registriert wird, oder indem sie als „ Q_SLOT “ der Klasse registriert wird. Alternativ kann eine benutzerdefinierte Methode mit der folgenden Syntax zu einer Objektdeklaration in einem QML-Dokument hinzugefügt werden:
function <functionName>([<parameterName>[: <parameterType>][, ...]]) [: <returnType>] { <body> }Methoden können zu einem QML-Typ hinzugefügt werden, um eigenständige, wiederverwendbare JavaScript-Codeblöcke zu definieren. Diese Methoden können entweder intern oder von externen Objekten aufgerufen werden.
Im Gegensatz zu Signalen müssen die Typen der Methodenparameter nicht deklariert werden, da sie standardmäßig den Typ „ var “ annehmen. Sie sollten sie jedoch deklarieren, um qmlcachegen dabei zu unterstützen, leistungsfähigeren Code zu generieren, und um die Wartbarkeit zu verbessern.
Der Versuch, zwei Methoden oder Signale mit demselben Namen im selben Typblock zu deklarieren, führt zu einem Fehler. Eine neue Methode kann jedoch den Namen einer bereits vorhandenen Methode des Typs wiederverwenden. (Dies sollte mit Vorsicht geschehen, da die vorhandene Methode dadurch möglicherweise ausgeblendet und nicht mehr zugänglich wird.)
Nachfolgend finden Sie ein „ Rectangle “ mit einer „ calculateHeight() “-Methode, die beim Zuweisen des Werts „ height “ aufgerufen wird:
import QtQuick
Rectangle {
id: rect
function calculateHeight(): real {
return rect.width / 2;
}
width: 100
height: calculateHeight()
}Wenn die Methode Parameter hat, sind diese innerhalb der Methode über ihren Namen zugänglich. Wenn unten auf das „ MouseArea “ geklickt wird, ruft dies die Methode „ moveTo() “ auf, die dann auf die empfangenen Parameter „ newX “ und „ newY “ zugreifen kann, um den Text neu zu positionieren:
import QtQuick
Item {
width: 200; height: 200
MouseArea {
anchors.fill: parent
onClicked: mouse => label.moveTo(mouse.x, mouse.y)
}
Text {
id: label
function moveTo(newX: real, newY: real) {
label.x = newX;
label.y = newY;
}
text: "Move me!"
}
}Angehängte Eigenschaften und angehängte Signal-Handler
Angehängte Eigenschaften und angehängte Signal-Handler sind Mechanismen, die es ermöglichen, Objekte mit zusätzlichen Eigenschaften oder Signal-Handlern auszustatten, die dem Objekt ansonsten nicht zur Verfügung stehen. Insbesondere ermöglichen sie Objekten den Zugriff auf Eigenschaften oder Signale, die speziell für das jeweilige Objekt relevant sind.
Bei der Implementierung eines QML-Typs kann man sich dafür entscheiden, in C++ einen angehängten Typ mit bestimmten Eigenschaften und Signalen zu erstellen. Instanzen dieses Typs können dann zur Laufzeit erstellt und an bestimmte Objekte angehängt werden, wodurch diese Objekte auf die Eigenschaften und Signale des „attaching type“ zugreifen können. Der Zugriff erfolgt, indem den Eigenschaften und den jeweiligen Signal-Handlern der Name des „attaching type“ vorangestellt wird.
Verweise auf angehängte Eigenschaften und Handler haben die folgende Syntax:
<AttachingType>.<propertyName>
<AttachingType>.on<SignalName>Beispielsweise verfügt der Typ „ ListView “ über eine angehängte Eigenschaft „ ListView.isCurrentItem “, die jedem Delegatenobjekt in einem „ ListView “ zur Verfügung steht. Diese kann von jedem einzelnen Delegatenobjekt verwendet werden, um festzustellen, ob es sich um das aktuell ausgewählte Element in der Ansicht handelt:
import QtQuick
ListView {
width: 240; height: 320
model: 3
delegate: Rectangle {
width: 100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow"
}
}In diesem Fall lautet der Name des anbringenden Typs „ ListView “ und die betreffende Eigenschaft ist „ isCurrentItem “, daher wird die angehängte Eigenschaft als „ ListView.isCurrentItem “ bezeichnet.
Ein angehängter Signal-Handler wird auf dieselbe Weise bezeichnet. Beispielsweise wird der angehängte Signal-Handler „ Component.onCompleted “ häufig verwendet, um JavaScript-Code auszuführen, sobald der Erstellungsprozess einer Komponente abgeschlossen ist. Im folgenden Beispiel wird, sobald die „ ListModel “ vollständig erstellt wurde, ihr Signal-Handler „ Component.onCompleted “ automatisch aufgerufen, um das Modell zu füllen:
import QtQuick
ListView {
width: 240; height: 320
model: ListModel {
id: listModel
Component.onCompleted: {
for (let i = 0; i < 10; i++) {
append({ Name: `Item ${i}` })
}
}
}
delegate: Text { text: index }
}Da der Name des anbringenden Typs „ Component “ lautet und dieser Typ über ein „ completed “-Signal verfügt, wird der angehängte Signal-Handler als „ Component.onCompleted “ bezeichnet.
Ein Hinweis zum Zugriff auf angehängte Eigenschaften und Signal-Handler
Ein häufiger Fehler besteht darin, anzunehmen, dass anfügbare Eigenschaften und Signal-Handler direkt von den untergeordneten Elementen des Objekts aus zugänglich sind, an das diese Attribute angefügt wurden. Dies ist nicht der Fall. Die Instanz des anfügenden Typs wird nur an bestimmte Objekte angefügt, nicht an das Objekt und alle seine untergeordneten Elemente.
Im Folgenden finden Sie beispielsweise eine modifizierte Version des früheren Beispiels mit angehängten Eigenschaften. Diesmal ist der Delegat ein „ Item “ und das farbige „ Rectangle “ ist ein untergeordnetes Element dieses Elements:
import QtQuick
ListView {
width: 240; height: 320
model: 3
delegate: Item {
width: 100; height: 30
Rectangle {
width: 100; height: 30
color: ListView.isCurrentItem ? "red" : "yellow" // WRONG! This won't work.
}
}
}Dies funktioniert nicht wie erwartet, da „ ListView.isCurrentItem “ nur an das Stamm-Delegatobjekt angefügt ist, nicht jedoch an dessen untergeordnete Elemente. Da das „ Rectangle “ ein untergeordnetes Element des Delegats ist und nicht das Delegat selbst, kann es nicht über „ ListView.isCurrentItem “ auf die angefügte Eigenschaft „ isCurrentItem “ zugreifen. Stattdessen sollte das Rechteck über das Stamm-Delegat auf „ isCurrentItem “ zugreifen:
ListView {
delegate: Item {
id: delegateItem
width: 100; height: 30
Rectangle {
width: 100; height: 30
color: delegateItem.ListView.isCurrentItem ? "red" : "yellow" // correct
}
}
}Nun verweist „ delegateItem.ListView.isCurrentItem “ korrekt auf die angehängte Eigenschaft „ isCurrentItem “ des Delegaten.
Enumerationsattribute
Enumerationen bieten eine feste Menge benannter Auswahlmöglichkeiten. Sie können in QML mit dem Schlüsselwort „ enum “ deklariert werden:
// MyText.qml
Text {
enum TextType {
Normal,
Heading
}
}Wie oben gezeigt, müssen Enumerationstypen (z. B. ` TextType`) und Werte (z. B. ` Normal`) mit einem Großbuchstaben beginnen.
Auf Werte wird über „ <Type>.<EnumerationType>.<Value> “ oder „ <Type>.<Value> “ verwiesen.
// MyText.qml
Text {
enum TextType {
Normal,
Heading
}
property int textType: MyText.TextType.Normal
font.bold: textType === MyText.TextType.Heading
font.pixelSize: textType === MyText.TextType.Heading ? 24 : 12
}Weitere Informationen zur Verwendung von Aufzählungen in QML finden Sie in der Dokumentation zu QML-Aufzählungen.
Die Möglichkeit, Aufzählungen in Qml zu deklarieren, wurde in Qt 5.10 eingeführt.
© 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.