QML 的核心特性之一是它使 QML 对象类型能够通过 QML 文档以轻量级的方式轻松定义,以便在您的应用程序中重复使用。
一、使用 QML 文件定义对象类型
1.1、命名自定义 QML 对象类型
要创建对象类型,应将 QML 文档放入名为 <TypeName>.qml 的文本文件中,其中 <TypeName> 是所需的类型名称。类型名称有以下要求:
- 必须由字母数字字符或下划线组成。
- 必须以大写字母开头。
该文档随后会被引擎自动识别为 QML 类型的定义。此外,在解析 QML 类型名称时,当引擎在直接目录中搜索时,以这种方式定义的类型会自动对同一目录中的其他 QML 文件可用。
1.2、自定义 QML 类型定义
例如,下面的文档声明了一个带有子 MouseArea 的 Rectangle。 该文档已保存到名为 SquareButton.qml 的文件中:
// SquareButton.qml
import QtQuick 2.0
Rectangle
{
property int side: 100
width: side; height: side
color: "red"
MouseArea
{
anchors.fill: parent
onClicked: console.log("Button clicked!")
}
}
由于该文件名为 SquareButton.qml,因此它现在可以被同一目录中的任何其他 QML 文件用作名为 SquareButton 的类型。例如,如果同一目录中有一个 myapplication.qml 文件,它可以引用 SquareButton 类型:
// myapplication.qml
import QtQuick 2.0
SquareButton {}
当这个 myapplication.qml 文档被引擎加载时,它将 SquareButton.qml 文档作为一个组件加载并实例化它以创建一个 SquareButton 对象。
注意:文件名的字母大小写在某些(特别是 UNIX)文件系统上很重要。 建议文件名大小写与所需 QML 类型名称的大小写完全匹配 - 例如,Box.qml 而不是 BoX.qml - 无论 QML 类型将部署到哪个平台。
1.3、内联组件
有时,为一种类型创建一个新文件可能很不方便,例如在多个视图中重用一个小委托时。
如果实际上不需要公开类型,而只需要创建一个实例,则可使用 Component。
但是如果想用组件类型声明属性,或者如果想在多个文件中使用它,在这种情况下,可以使用内联组件。 内联组件在文件中声明一个新组件。 语法是:
component <component name> : BaseType {
// 在这里声明属性和绑定
}
在声明内联组件的文件中,可以简单地通过其名称引用该类型。
// 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
}
}
注意:内联组件不与声明它们的组件共享它们的作用域。在以下示例中,当文件 B.qml 中的 A.MyInlineComponent 创建时,将发生 ReferenceError,因为 root 在 B.qml 中不作为 id 存在。 因此,建议不要引用内联组件中不属于它的对象。
// A.qml
import QtQuick 2.15
Item
{
id: root
property string message: "From A"
component MyInlineComponent : Item
{
Component.onCompleted: console.log(root.message)
}
}
// B.qml
import QtQuick 2.15
Item
{
A.MyInlineComponent {}
}
注意:内联组件不能嵌套。
二、自定义类型的可访问属性
.qml 文件中的根对象定义定义了可用于 QML 类型的属性。属于这个根对象的所有属性、信号和方法,无论它们是自定义声明的,还是来自根对象的 QML 类型,都可以从外部访问,并且可以为这种类型的对象读取和修改。
例如,上面 SquareButton.qml 文件中的根对象类型是 Rectangle。 这意味着可以为 SquareButton 对象修改由 Rectangle 类型定义的任何属性。
修改自带属性:
// application.qml
import QtQuick 2.0
Column
{
SquareButton { side: 50 }
SquareButton { x: 50; color: "blue" }
SquareButton { radius: 10 }
}
访问自定义属性、方法和信号:
// SquareButton.qml
import QtQuick 2.0
Rectangle
{
id: root
property bool pressed: mouseArea.pressed
signal buttonClicked(real xPos, real yPos)
function randomizeColor()
{
root.color = Qt.rgba(Math.random(), Math.random(), Math.random(), 1)
}
property int side: 100
width: side; height: side
color: "red"
MouseArea
{
id: mouseArea
anchors.fill: parent
onClicked: (mouse)=> root.buttonClicked(mouse.x, mouse.y)
}
}
任何 SquareButton 对象都可以使用已添加到根 Rectangle 的 press 属性、buttonClicked 信号和 randomizeColor() 方法:
// application.qml
import QtQuick 2.0
SquareButton
{
id: squareButton
onButtonClicked: (xPos, yPos)=>
{
console.log("Clicked", xPos, yPos)
randomizeColor()
}
Text { text: squareButton.pressed ? "Down" : "Up" }
}
SquareButton.qml 中定义的任何 id 值都不能被 SquareButton 对象访问,因为 id 值只能从声明组件的组件范围内访问。