Defining Object Types through QML Documents
QML的核心特性之一是轻松定义QML对象类型. 标准的Qt Quick模块提供多种类型, 如Rectangle, Text和Image. 此外, 你也可以自定义QML类型.
在QML文件中定义对象类型
自定义对象类型
为了创建一个对象类型, 应将QML文档命名为 <TypeName>.qml, <TypeName> 是类型名称, 它的要求如下:
- 必须由字母数字字符或下划线组成.
- 必须以大写字母开头.
QML引擎自动将文档识别为QML类型定义. 此外, 当解析QML类型名称时, 对象类型自动用于与同级目录的其他QML文件.
自定义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!") } }
现在, 你可以在同级目录的其他QML文件中使用名为SquareButton
类型. 如下所示, 如果myapplication.qml
文件在同级目录, 它可以引用SquareButton
类型:
// myapplication.qml import QtQuick 2.0 SquareButton {}
上述代码创建一个SquareButton.qml
对象, 它定义一个100*100的红色Rectangle, 并带有一个MouseArea. 当QML引擎加载myapplication.qml
时, 也会以组件方式加载SquareButton.qml
文件, 并实例化一个SquareButton
对象.
在SquareButton.qml
中声明的SquareButton
类型, 封装了一个QML对象树. QML引擎实例化SquareButton
对象时, 它也会实例化一个Rectangle对象树.
注意: 文件名的大小写在某些文件系统(尤其是UNIX)中非常重要. 无论部署在哪个平台, 建议文件名与QML类型名称完全匹配, 如Box.qml
, 而不是BoX.qml
.
内联组件
有时, 你不方便为一个类型创建一个新文件, 如多个视图中复用的委托部件. 如果你不需要一个公开类型, 只想创建一个实例, Component可以满足要求. 但是, 如果你想使用组件类型声明属性, 或者在多个文件使用它, Component无法满足要求. 在这种情况下, 你可以使用内联组件. 内联组件是在文件中声明一个新组件. 语法是:
component <component name> : BaseType { // declare properties and bindings here }
在声明内联组件的文件中, 可以简单地使用名称引用组件:
// 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
, 因为在B.qml
中, root
不能作为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 {} }
注意: 内联组件不能嵌套.
导入在当前目录之外定义的类型
如果SquareButton.qml
和myapplication.qml
不在同级目录, 则myapplication.qml
必须在导入语句中提供SquareButton
类型. 它可以从文件系统的相对路径导入, 也可以作为已安装的模块导入; 详见module.
自定义类型的可访问属性
The root object definition in a .qml file defines the attributes that are available for a QML type. All properties, signals and methods that belong to this root object - whether they are custom declared, or come from the QML type of the root object - are externally accessible and can be read and modified for objects of this type.
For example, the root object type in the SquareButton.qml
file above is Rectangle. This means any properties defined by the Rectangle type can be modified for a SquareButton
object. The code below defines three SquareButton
objects with customized values for some of the properties of the root Rectangle object of the SquareButton
type:
// application.qml import QtQuick 2.0 Column { SquareButton { side: 50 } SquareButton { x: 50; color: "blue" } SquareButton { radius: 10 } }
自定义QML类型的对象可访问的属性包括为对象额外定义的任何 自定义属性, 方法 和 信号. 例如, 假设SquareButton.qml
中的Rectangle定义如下, 并定义额外的属性, 方法和信号:
// 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: root.buttonClicked(mouse.x, mouse.y) } }
任何SquareButton
对象都可以使用pressed
属性, buttonClicked
信号, randomizeColor
()方法:
// application.qml import QtQuick 2.0 SquareButton { id: squareButton onButtonClicked: { console.log("Clicked", xPos, yPos) randomizeColor() } Text { text: squareButton.pressed ? "Down" : "Up" } }
注意: SquareButton.qml
中定义的id
不能访问SquareButton
对象, id
只能从声明组件的作用域访问. SquareButton
对象不能引用MouseArea子对象, 如果它的id
是root
, 而不是SquareButton
, 则不会与SquareButton.qml
的根对象id
冲突, 因为两者不在同一作用域声明.