通过QML文档定义对象类型

描述QML文档如何作为可重用的类型定义

QML的核心特性之一是它能够通过QML文档以轻量级的方式轻松定义QML对象类型,以满足各个QML应用程序的需求。标准的Qt Quick模块提供了各种类型,如Rectangle、Text和Image,用于构建QML应用程序;除此之外,您可以轻松定义自己的QML类型,以便在应用程序中重复使用。这种创建自定义类型的能力构成了任何QML应用程序的基础。

使用QML文件定义对象类型

命名自定义QML对象类型

要创建一个对象类型,QML文档应放置在一个名为.qml的文本文件中,其中是所需的类型名称。类型名称有以下要求:

  • 它必须由字母数字字符或下划线组成。

  • 它必须以大写字母开头。

然后,引擎会自动将此文档识别为QML类型的定义。此外,以这种方式定义的类型会自动提供给与引擎在同一本地目录中的其他QML文件,因为引擎在解析QML类型名称时会搜索当前目录。

注意

QML引擎不会自动以这种方式搜索远程目录。如果您的文档是通过网络加载的,您必须添加一个qmldir文件。请参阅导入QML文档目录

自定义QML类型定义

例如,下面是一个声明了一个带有子元素MouseArea的Rectangle的文档。该文档已保存到名为SquareButton.qml的文件中:

由于文件名为SquareButton.qml现在可以在同一目录下的任何其他QML文件中将其用作名为SquareButton的类型。例如,如果在同一目录中有一个myapplication.qml文件,它可以引用SquareButton类型:

../_images/documents-definetypes-simple.png

这将创建一个100 x 100的红色矩形,内部包含一个MouseArea,如SquareButton.qml中所定义。当引擎加载此myapplication.qml文档时,它会将SquareButton.qml文档作为组件加载并实例化以创建一个SquareButton对象。

SquareButton 类型封装了在 SquareButton.qml 中声明的 QML 对象树。当 QML 引擎从该类型实例化一个 SquareButton 对象时,它实际上是从 SquareButton.qml 中声明的 Rectangle 树实例化一个对象。

注意

在某些(特别是UNIX)文件系统中,文件名的大小写是敏感的。建议文件名的大小写与所需的QML类型名称的大小写完全匹配 - 例如,Box.qml 而不是 BoX.qml - 无论QML类型将部署到哪个平台。

内联组件

有时候,为某种类型创建一个新文件可能会很不方便,例如在多个视图中重复使用一个小型委托时。如果你实际上不需要暴露该类型,而只需要创建一个实例,Component 是一个选择。但如果你想声明具有组件类型的属性,或者你想在多个文件中使用它,Component 就不是一个选择。在这种情况下,你可以使用内联组件。内联组件在一个文件内部声明一个新组件。其语法如下:

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

在声明内联组件的文件中,可以通过其名称简单地引用类型。

// Images.qml
import QtQuick

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

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

Item {
    id: root
    property string message: "From A"
    component MyInlineComponent : Item {
        Component.onCompleted: console.log(root.message)
    }
}
// B.qml
import QtQuick

Item {
    A.MyInlineComponent {}
}

注意

内联组件不能嵌套。

导入当前目录外定义的类型

如果 SquareButton.qml 不在与 myapplication.qml 相同的目录中,则需要在 myapplication.qml 中通过 import 语句特别使 SquareButton 类型可用。它可以从文件系统中的相对路径导入,或者作为已安装的模块导入;有关更多详细信息,请参见 module

自定义类型的可访问属性

在.qml文件中的根对象定义定义了QML类型可用的属性。属于这个根对象的所有属性、信号和方法——无论是自定义声明的,还是来自根对象的QML类型的——都可以从外部访问,并且可以读取和修改这种类型的对象。

例如,上面SquareButton.qml文件中的根对象类型是Rectangle。这意味着可以为SquareButton对象修改由Rectangle类型定义的任何属性。下面的代码定义了三个SquareButton对象,并为SquareButton类型的根Rectangle对象的一些属性设置了自定义值:

../_images/documents-definetypes-attributes.png

自定义QML类型对象可访问的属性包括任何为对象额外定义的自定义属性方法信号。例如,假设SquareButton.qml中的Rectangle被定义如下,具有额外的属性、方法和信号:

任何 SquareButton 对象都可以使用已添加到根矩形的 pressed 属性、buttonClicked 信号和 randomizeColor() 方法:

请注意,在SquareButton.qml中定义的任何id值对于SquareButton对象都是不可访问的,因为id值只能在声明组件的组件范围内访问。上面的SquareButton对象定义不能引用mouseArea来引用MouseArea子对象,如果它的idroot而不是squareButton,这不会与SquareButton.qml中定义的根对象的相同值的id冲突,因为两者将在不同的范围内声明。