Während in Qt 6.0 große Änderungen erwartet werden, hat QML in 5.15 bereits einige neue Sprachfeatures erhalten. Lesen Sie weiter, um mehr über erforderliche Eigenschaften, integrierte Komponenten und nullische Koaleszenz zu erfahren.
Erforderliche Eigenschaften
Manchmal haben Sie Komponenten, für die einige Eigenschaften festgelegt werden müssen, und die keine wirklich guten Standardeinstellungen haben. Beispielsweise können Sie sich um die Zugänglichkeit Ihrer Schaltflächen kümmern, also erstellen Sie einen AccessibleButton, der immer eine Beschreibung haben sollte.
// AccessibleButton.qml Button { property string description Accessible.description: description }
Nur weil eine Schaltfläche eine Beschreibungseigenschaft hat, bedeutet dies jedoch nicht, dass jemand anderes sie festlegen wird. Sie oder Ihr Kollege könnten die Bean also irgendwann instanziieren mit:
AccessibleButton { onClicked: (mouse) => { /* fancy business logic here */ } }
Die Beschreibung ist jetzt nur noch ein leerer String! Sicher, Sie könnten ihm einen Standardwert geben, aber welchen? "Taste"? Es ist kaum hilfreich. "Sollten Sie es nicht melden"? Zumindest Tests können dies erkennen. Aber wäre es nicht nützlicher, wenn die QML-Engine diese Eigenschaft setzen könnte?
Vor Qt 5.15 gab es leider keine Möglichkeit sicherzustellen, dass die Beschreibung gesetzt wurde. Aber seit Qt 5.15 wird es möglich:
Button { required property string description Accessible.description: description }
Wenn jetzt ein AccessibleButton erstellt wird und keine Beschreibung angegeben wird, wird die gesamte Anwendung nicht gestartet. Dies ist jedoch nicht möglich, wenn die Komponente dynamisch erstellt wird, beispielsweise über einen Loader. In diesem Fall wird nur eine Laufzeitwarnung ausgegeben.
Es ist auch geplant, qmllint und QtCreator mehr Tool-Unterstützung hinzuzufügen, um eine Warnung anzuzeigen, wenn erforderliche Eigenschaften nicht gesetzt sind.
Erforderliche Eigenschaften und Delegierte (Delegierte)
Außerdem spielen erforderliche Eigenschaften bei Delegaten eine besondere Rolle. Wie Sie vielleicht wissen, können Delegaten direkt über den Namen auf Modellrollen eines bereitgestellten Modells sowie auf einige andere Eigenschaften wie Modell und Index zugreifen.
ListView { model: root.myModel delegate: Text { id: delegate color: index % 2 ? "gray" : "black" text: description } }
Und wenn Ihre Delegaten keine erforderlichen Eigenschaften enthalten, ändert sich hier nichts. Wenn sie jedoch mindestens eine erforderliche Eigenschaft enthalten, sind diese Namen nicht mehr verfügbar. Stattdessen müssen Sie genau auswählen, indem Sie sie als erforderliche Eigenschaften angeben.
ListView { model: root.myModel delegate: Text { id: delegate required property int index required property string description color: index % 2 ? "gray" : "black" text: description } }
Die QML-Engine legt dann die erforderlichen Eigenschaften fest. Beachten Sie, dass es einen großen Unterschied zwischen dem neuen Ansatz und dem alten gibt, wenn Ihr Modell bearbeitbar war: Mit dem alten Ansatz könnten Sie schreiben:
Text { id: delegate Component.onCompleted: description = "My fancy new text" }
und das Modell würde entsprechend aktualisiert werden. Aber wenn doch
Text { id: delegate required property string description Component.onCompleted: delegate.description = "My fancy new text" }
dann wird die Bindung an die Beschreibung unterbrochen (und die QML-Engine gibt eine Warnung aus) und das Modell wird nicht aktualisiert. Dieses Verhalten wurde gewählt, um sicherzustellen, dass sich Komponenten nicht zu unterschiedlich verhalten, wenn sie in Delegaten und außerhalb von ihnen verwendet werden. Außerdem wollten die Entwickler niemanden ermutigen, obligatorische Eigenschaftszuweisungen vorzunehmen (weil dies Bindungen im Allgemeinen brechen würde).
Wenn Sie den Wert des Modells wirklich aktualisieren möchten, gibt es natürlich eine Möglichkeit, dies zu erreichen: Machen Sie das Modell zu einer erforderlichen Eigenschaft und schreiben Sie:
Component.onCompleted: model.description= "My fancy new text"
Die Entwickler empfehlen, dass Sie immer erforderliche Eigenschaften für Delegaten verwenden. Dies vermeidet ungelernte Suchen, die für Tools problematisch sind und tendenziell langsamer sind.
Inline-Komponenten
Ein weiteres neues Feature in 5.15 sind Inline-Komponenten. Wie der Name schon sagt, ermöglichen sie Ihnen, eine neue Komponente innerhalb einer Datei zu definieren. Die grundlegende Syntax lautet:
component <component name> : BaseType { // declare properties and bindings here }
Innerhalb der Datei können Sie über den Namen auf die neue Komponente verweisen, als ob sie in einer eigenen Datei definiert wäre. Nehmen wir die Komponente LabeledImage als Beispiel, um zu zeigen, wie das funktioniert:
// Images.qml import QtQuick 2.15 Item { component LabeledImage: Column { property alias source: image.source property alias caption: text.text Image { id: image width: 50 height: 50 } Text { id: text font.bold: true } } Row { LabeledImage { id: before source: "before.png" caption: "Before" } LabeledImage { id: after source: "after.png" caption: "After" } } property LabeledImage selectedImage: before }
Es ist auch möglich, die Komponente in anderen Dateien zu referenzieren. In diesem Fall müssen Sie seinen Namen dem Namen der enthaltenden Komponente voranstellen:
// LabeledImageBox.qml import QtQuick 2.15 Rectangle { property alias caption: image.caption property alias source: image.source border.width: 2 border.color: "black" Images.LabeledImage { id: image } }
Sie fragen sich vielleicht, warum Inline-Komponenten benötigt werden, wenn QML bereits einen Komponententyp hat. Wenn Sie sich die vorherigen Beispiele ansehen, können Sie sehen, dass Sie mit Inline-Komponenten die folgenden Dinge tun können, die mit Component nicht möglich sind:
• Sie können eine Komponente ohne die zusätzlichen Kosten für die Verwendung von Loader instanziieren.
• Sie können den Komponententyp in Eigenschaftsdeklarationen verwenden.
• Sie können auf eine Komponente in anderen Dateien als derjenigen verweisen, in der sie definiert ist.
NULL-Koaleszenz
Das neueste neue Sprachfeature wurde von Qt-Praktikant Maximilian Goldstein implementiert. Während QML im Allgemeinen nur EcmaScript 6 unterstützt, hat Max Unterstützung für eine neue Sprachfunktion hinzugefügt, die derzeit dem neuesten EcmaScript-Standard hinzugefügt wird: Nullish Coalescing . Zitat von MDN:
nullischer Koaleszenzoperator ist ein boolescher Operator, der seinen rechten Operanden zurückgibt, wenn sein linker Operand null oder undefiniert ist, oder ansonsten seinen linken Operanden zurückgibt.
Hier ist ein Beispiel dafür, wie es in QML verwendet werden kann, um Eigenschaften von JSON festzulegen und angemessene Standardwerte bereitzustellen, wenn keine bereitgestellt wurden.
Item { property var settings property int brightness: settings.brightness ?? 100 property color color: settings.color ?? "blue" Component.onCompleted: settings = JSON.parse(settingsString) }
Beachten Sie, dass Sie || nicht verwenden konnten Anstatt von ?? für Helligkeit (Helligkeit), da settings.brightness 0 sein könnte, in diesem Fall würde es den Standardwert erhalten.
Warte ab!
Mit Qt 6 am Horizont werden mit Sicherheit noch viele weitere Änderungen an QML vorgenommen. Neben der Modernisierung der Interna der QML-Engine wollen Entwickler die statische Typisierung verwenden, um sowohl schnelleren Code zu generieren (einschließlich der Kompilierung nach C++) als auch um die Tools zu verbessern. Während sich die Entwickler für die erste Version von 6.0 auf diese großen Themen konzentrieren, bleiben sie außerdem offen für kleine Verbesserungen der Lebensqualität: Optionales Verketten oder Hinzufügen von Unterstützung für die Abruf-API sind nur zwei Beispiele für Feature-Anfragen aus der Community. eine größere Zeitleiste wird als .x betrachtet (aber nicht die ursprüngliche Version 6.0).