Skip to main content

Qt 5.15中新的QML语言特性

Comments

本文翻译自:New QML language features in Qt 5.15

原文作者:Fabian Kosmale

校审:Kenny Zhang

随着Qt 6.0即将带来的重大变化,QML已在5.15中加入了一些新的语言特性。继续阅读以了解required properties(必备属性), inline components(内联组件) 和nullish coalescing(空值合并)。

Required Properties(必备属性)

有时,您的组件需要设置一些属性,但没有合适的默认值。例如,您可能关心按钮的易访问性(Accessibility),因此当您创建了一个AccessibleButton控件,它至少应该有一个description属性。

// AccessibleButton.qml
Button {
property string description
Accessible.description: description
}

但是,按钮具有description属性这一事实并不意味着任何人都会设置它。所以您或您的同事可能会在某个时候用以下代码实例化组件:

AccessibleButton {
onClicked: (mouse) => { /* fancy business logic here */ }
}

关于易访问性就讲到这里:现在description属性只是一个空字符串!当然,您可以为属性设置一个默认值,但是用哪个呢?“Button”基本没用。"您不应该听到这个"?好吧,至少QA现在可能会针对它。但是,如果QML引擎知道需要设置此属性,不是更有用吗?

不幸的是,在Qt 5.15之前没有办法强制设置description属性。但从Qt 5.15开始,这就成为可能:

Button {
required property string description
Accessible.description: description
}

现在,如果创建一个AccessibleButton,但没有设置description属性,那么整个应用程序将无法启动。但如果该组件是动态创建的(例如通过Loader加载),则无法做到这一点。这种情况下,将仅出现运行时警告。

我们还计划为qmllint和QtCreator添加更多的工具支持,以便在未设置Required Properties时显示警告。

Required Properties和Delegates

此外,Required Properties在Delegates中扮演着特殊的角色。正如您可能知道的,Delegates可以通过名称以及其他属性,如model和index,直接访问所提供的模型角色。

ListView {
model: root.myModel
delegate: Text {
id: delegate
color: index % 2 ? "gray" : "black"
text: description
}
}

如果您的Delegates不包含Required Properties,则此处不会发生任何更改。但是,如果它们包含至少一个Required Properties,那么这些名称就不能再访问了。相反,您必须将它们显式的指定为Required Properties。

ListView {
model: root.myModel
delegate: Text {
id: delegate
required property int index
required property string description
color: index % 2 ? "gray" : "black"
text: description
}
}

然后QML引擎将相应设置Required Properties。请注意,如您的model是可编辑的,新方法和旧方法之间有一个重要的区别:使用旧方法,您可以这样写代码:

Text {
id: delegate
Component.onCompleted: description = "My fancy new text"
}

model也会相应更新。但如果你这样写代码

Text {
id: delegate
required property string description
Component.onCompleted: delegate.description = "My fancy new text"
}

然后,description的绑定将被破坏(QML引擎将会打印警告),model将不会被更新。我们决定采用这种行为,以确保无论在delegates中或在delegates之外使用,components的行为不会有太大的差异。此外,我们也不鼓励任何人对属性执行命令式赋值(因为这通常会破坏绑定)。

如果您确实想要更新model的值,当然还有一种办法可以实现:将model设置为Required Properties并用以下代码


Component.onCompleted: model.description= "My fancy new text"

我们建议您始终在Delegates中使用Required Properties。这避免了非限定查找,后者对工具来说是个问题,并往往会降低处理速度。

Inline Components(内联组件)

Qt 5.15中的另一个新特性是内联组件。顾名思义,它们允许您在文件中定义一个新组件。基本语法是


component <component name> : BaseType {
// declare properties and bindings here
}

在文件内部,您可以通过名称引用新组件,就像在其自己的文件中定义的一样。让我们以LabeledImage组件为例来说明其工作原理:

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

您也可以在其它文件中引用该组件。在这种情况下,您需要在其名字之前加上包含其组件的名称:

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

您可能会想,既然QML已经有了组件类型,为什么还要使用内联组件呢?查看前面的示例,我们可以看到,内联组件使您可以执行组件无法执行的以下操作:

  • 您可以在没有Loader开销的情况下创建组件实例。
  • 您可以在属性声明中使用组件类型。
  • 您可以在定义组件的文件之外的其他文件中引用该组件。

希望您能和我们一样方便地找到内联组件!

Nullish Coalescing(空值合并)

最后一个新语言特性是由我们的实习生Maximilian Goldstein实现的。虽然QML通常只支持EcmaScript 6,但是Maximilian为一个即将提出的语言特性增加了支持,该特性正在被添加到最新的EcmaScript标准中:空值合并。引用MDN:

空值合并操作符(??)是一个逻辑操作符,当其左侧操作数为空或未定义时,返回其右侧操作数,否则返回其左侧操作数。

有关详细信息,请参阅MDN页面。下面是一个示例,演示如何在QML中使用它来设置JSON中的属性,并在未提供属性的情况下提供合理的默认值。

Item {
property var settings
property int brightness: settings.brightness ?? 100
property color color: settings.color ?? "blue"
Component.onCompleted: settings = JSON.parse(settingsString)
}

注意我们在设置brightness时不能用“||”代替“??”。因为settings.brightness可能已经是0,在这种情况下,我们将获取默认值。

展望

随着Qt 6的到来,QML将迎来更多改变。除了改进QML引擎的内部机制之外,我们还希望利用静态类型来生成更快的代码(包括编译成C++),并改进我们的工具链。此外,虽然我们在最初的6.0版本中侧重那些大主题,但我们也会在那些小改进上花时间:optional chaining或添加对fetch API的支持就是两个来自Qt社区的特性需求示例,我们会在较高的6.x版本基线中考虑 (不是最初的6.0版本)。您希望在QML中看到什么其它的特性吗?请在bug跟踪系统中创建一个提议。未来由Qt写就!

Blog Topics

Comments

Subscribe to our blog

Try Qt 6.11 Now!

Download the latest release here: www.qt.io/download

Qt 6.11 is now available, with new features and improvements for application developers and device creators.

We're Hiring

Check out all our open positions here and follow us on Instagram to see what it's like to be #QtPeople.