Определение объектных типов через документы QML
Одной из основных особенностей QML является то, что он позволяет легко и упрощенно определять объектные типы QML с помощью документов QML в соответствии с потребностями отдельных приложений QML. Стандартный модуль Qt Quick для создания приложения QML предоставляет различные типы, такие как Rectangle
, Text
и Image
. Помимо этого, вы можете легко определить свои собственные типы QML для повторного использования в вашем приложении. Эта возможность создавать свои собственные типы формирует строительные блоки любого приложения QML.
Определение объектного типа с помощью файла QML
Именование пользовательских объектных типов QML
Чтобы создать объектный тип, документ QML должен быть помещен в текстовый файл с именем <TypeName>.qml
, где <TypeName>
– желаемое имя типа. Имя типа имеет следующие требования:
- оно должно состоять из буквенно-цифровых символов или знаков подчеркивания;
- оно должно начинаться с заглавной буквы.
Затем этот документ автоматически распознается движком как определение типа QML. Кроме того, тип, определенный таким образом, автоматически становится доступным для других файлов QML в том же каталоге, поскольку при разрешении имен типов QML движок ищет их в том же каталоге.
Определение пользовательского типа QML
Например, ниже представлен документ, в котором объявляется Rectangle
с дочерним элементом MouseArea
. Документ был сохранен в файл с именем 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, теперь его можно использовать как тип с именем SquareButton
в любом другом файле QML в том же каталоге. Например, если бы в том же каталоге был файл myapplication.qml, он мог бы ссылаться на тип SquareButton
:
// myapplication.qml
import QtQuick 2.0
SquareButton {}
Этот код создает красный прямоугольник Rectangle
100x100 с внутренним элементом MouseArea
, как определено в SquareButton.qml. Когда этот документ myapplication.qml загружается движком, он загружает документ SquareButton.qml как компонент и создает его экземпляр для создания объекта SquareButton
.
Тип SquareButton
инкапсулирует дерево объектов QML, объявленное в SquareButton.qml. Когда движок QML создает экземпляр объекта SquareButton
из этого типа, он создает экземпляр объекта из дерева Rectangle
, объявленного в SquareButton.qml.
Примечание: в некоторых файловых системах (особенно в UNIX) важен регистр букв имени файла. Рекомендуется, чтобы регистр имени файла точно соответствовал регистру имени желаемого типа QML (например, Box.qml, а не BoX.qml) независимо от платформы, на которой будет развернут этот тип QML.
Встроенные компоненты
Иногда может быть неудобно создавать новый файл для типа, например, при повторном использовании небольшого делегата в нескольких представлениях. Если вам на самом деле не нужно раскрывать тип, а нужно только создать экземпляр, подходящим вариантом будет Component
. Но если вы хотите объявить свойства с типами компонентов или использовать их в нескольких файлах, Component
не подходит. В этом случае вы можете использовать встроенные компоненты. Встроенные компоненты объявляют новый компонент внутри файла. Синтаксис для этого
component <имя компонента> : БазовыйТип {
// объявляем здесь свойства и привязки
}
Внутри файла, который объявляет встроенный компонент, на этот тип можно ссылаться просто по его имени.
// 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
}
}
Примечание. Встроенные компоненты не разделяют свою область видимости с компонентом, в котором они объявлены. В следующем примере при создании A.MyInlineComponent
в файле B.qml возникает ReferenceError
, поскольку root
не существует в качестве id
в B.qml. Поэтому рекомендуется не ссылаться на объекты во встроенном компоненте, которые не являются его частью.
// 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, тип SquareButton
необходимо было бы специально сделать доступным с помощью инструкции import
в myapplication.qml. Его можно было импортировать по относительному пути в файловой системе или как установленный модуль; более подробную информацию о модулях смотрите в соответствующем разделе.
Доступные атрибуты пользовательских типов
Определение корневого объекта в файле .qml определяет атрибуты, доступные для типа QML. Все свойства, сигналы и методы, принадлежащие этому корневому объекту, независимо от того, объявлены ли они пользователем или исходят из типа QML корневого объекта, доступны извне и могут быть прочитаны и изменены для объектов этого типа.
Например, тип корневого объекта в приведенном выше файле SquareButton.qml – Rectangle
. Это означает, что любые свойства, определенные типом Rectangle
, могут быть изменены для объекта SquareButton
. Код ниже определяет три объекта SquareButton
с настроенными значениями для некоторых свойств корневого объекта Rectangle
типа SquareButton
:
// application.qml
import QtQuick 2.0
Column {
SquareButton { side: 50 }
SquareButton { x: 50; color: "blue" }
SquareButton { radius: 10 }
}
Атрибуты, доступные для объектов пользовательского типа QML, включают в себя любые пользовательские свойства, методы и сигналы, которые были дополнительно определены для объекта. Например, предположим, что Rectangle
в SquareButton.qml был определен следующим образом с дополнительными свойствами, методами и сигналами:
// 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
может использовать свойство pressed
, сигнал buttonClicked
и метод randomizeColor()
, которые были добавлены к корневому объекту Rectangle
:
// application.qml
import QtQuick 2.0
SquareButton {
id: squareButton
onButtonClicked: (xPos, yPos)=> {
console.log("Clicked", xPos, yPos)
randomizeColor()
}
Text { text: squareButton.pressed ? "Down" : "Up" }
}
Обратите внимание, что любое из значений id
, определенных в SquareButton.qml, недоступно для объектов SquareButton
, поскольку значения id
доступны только из области видимости компонента, в которой объявлен этот компонент. Приведенное выше определение объекта SquareButton
не может ссылаться на mouseArea
, чтобы ссылаться на дочерний элемент MouseArea
, и если бы у него был id root
, а не squareButton
, это не конфликтовало бы с id
с тем же значением для корневого объекта, определенного в SquareButton.qml. поскольку они будут объявлены в разных областях видимости.