Определение объектных типов через документы QML

Добавлено 11 мая 2022 в 17:13

Одной из основных особенностей 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.qmlRectangle. Это означает, что любые свойства, определенные типом 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. поскольку они будут объявлены в разных областях видимости.

Теги

GUI / Графический интерфейс пользователяQMLQtQtQuickПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.