Spec-Zone.ru › Qt 6.1

Охват и разрешение имён

Связывания свойств QML, встроенные функции и импортированные JavaScript-файлы выполняются в области видимости JavaScript. Область видимости определяет, к каким переменным может получить доступ выражение, и какая переменная имеет приоритет при конфликте имён.

Поскольку встроенный механизм области видимости JavaScript очень прост, QML расширяет его, чтобы он более естественно соответствовал расширениям языка QML.

Область видимости JavaScript

Расширения области видимости QML не влияют на естественное определение области видимости JavaScript. Разработчики JavaScript могут использовать свои существующие знания при программировании функций, связывании свойств или импортированных JavaScript-файлов в QML.

В следующем примере метод addConstant() будет добавлять 13 к переданному параметру так, как ожидает программист, независимо от значения свойств объекта QML a и b.

QtObject {
    property int a: 3
    property int b: 9

    function addConstant(b) {
        var a = 13;
        return b + a;
    }
}

То, что QML соблюдает стандартные правила области видимости JavaScript, относится и к связываниям. Это совершенно ужасное, отвратительное связывание присвоит 12 свойству объекта QML a.

QtObject {
    property int a

    a: { var a = 12; a; }
}

Каждое JavaScript-выражение, функция или файл в QML имеет собственный уникальный объект переменных. Локальные переменные, объявленные в одном, никогда не будут конфликтовать с локальными переменными, объявленными в другом.

Имена типов и импортированные JavaScript-файлы

Документы QML включают операторы импорта, которые определяют имена типов и JavaScript-файлы, видимые для документа. Помимо использования в самом объявлении QML, имена типов используются кодом JavaScript при обращении к присоединённым свойствам и значениям перечислений.

Эффект импорта распространяется на каждое связывание свойств и JavaScript-функцию в документе QML, даже на те, что находятся во вложенных встроенных компонентах. Следующий пример демонстрирует простой QML-файл, который обращается к некоторым значениям перечислений и вызывает импортированную JavaScript-функцию.

import QtQuick 2.0
import "code.js" as Code

ListView {
    snapMode: ListView.SnapToItem

    delegate: Component {
        Text {
            elide: Text.ElideMiddle
            text: "A really, really long string that will require eliding."
            color: Code.defaultColor()
        }
    }
}

Объект области видимости связывания

Объект, у которого есть связывание свойства, известен как объект области видимости связывания. В следующем примере объектом области видимости связывания является объект Item.

Item {
    anchors.left: parent.left
}

Связывания могут получить доступ к свойствам объекта области видимости без квалификации. В предыдущем примере связывание обращается к свойству Item parent напрямую, без необходимости любого вида префикса объекта. QML внедряет более структурированный, объектно-ориентированный подход к JavaScript и, следовательно, не требует использования JavaScript-свойства this.

При обращении к присоединённым свойствам из связываний необходимо соблюдать осторожность из-за их взаимодействия с объектом области видимости. Понятийно, присоединённые свойства существуют на всех объектах, даже если они действуют только на подмножество их. Следовательно, неопределённый доступ к присоединённым свойствам всегда будет разрешаться в присоединённое свойство объекта области видимости, что не всегда соответствует намерениям программиста.

Например, тип PathView присоединяет интерполированные свойства значений к своим делегатам в зависимости от их положения в пути. Так как PathView осмысленно присоединяет эти свойства только к корневому объекту в делегате, любой дочерний объект, который обращается к ним, должен явно указать корневой объект, как показано ниже.

PathView {
    delegate: Component {
        Rectangle {
            id: root
            Image {
                scale: root.PathView.scale
            }
        }
    }
}

Если объект Image опустил префикс root, он непреднамеренно обратится к не установленным PathView.scale присоединённым свойствам к себе.

Область видимости компонента

Каждый QML-компонент в документе QML определяет логическую область видимости. Каждый документ имеет по крайней мере один корневой компонент, но также может иметь и другие вложенные подкомпоненты. Область видимости компонента — это объединение идентификаторов объектов внутри компонента и свойств корневого объекта компонента.

Item {
    property string title

    Text {
        id: titletype
        text: "<b>" + title + "</b>"
        font.pixelSize: 22
        anchors.top: parent.top
    }

    Text {
        text: titletype.text
        font.pixelSize: 18
        anchors.bottom: parent.bottom
    }
}

В примере выше показан простой QML-компонент, который отображает строку богатого текста заголовка вверху и меньшую копию того же текста внизу. Первый тип Text напрямую обращается к свойству компонента title при формировании отображаемого текста. То, что свойства корневого типа напрямую доступны, делает распределение данных по компоненту тривиальным.

Второй тип Text использует идентификатор для прямого доступа к тексту первого. Идентификаторы указываются программистом QML явно, поэтому они всегда имеют приоритет над другими именами свойств (кроме тех, что находятся в области видимости JavaScript). Например, в маловероятном случае, если у объекта области видимости связывания scope object в предыдущем примере было свойство titletype, идентификатор titletype всё равно имел бы приоритет.

Иерархия экземпляров компонентов

В QML экземпляры компонентов объединяют свои области видимости компонентов, чтобы образовать иерархию области видимости. Экземпляры компонентов могут напрямую получать доступ к областям видимости компонентов своих предков.

Самый простой способ продемонстрировать это — с помощью вложенных подкомпонентов, чьи области видимости компонентов неявно охватываются как дочерние по отношению к внешнему компоненту.

Item {
    property color defaultColor: "blue"

    ListView {
        delegate: Component {
            Rectangle {
                color: defaultColor
            }
        }
    }
}

Иерархия экземпляров компонентов позволяет экземплярам компонента делегата получать доступ к свойству defaultColor типа Item. Конечно, если бы у компонента делегата было свойство с именем defaultColor, оно имело бы приоритет.

Иерархия области видимости экземпляров компонентов распространяется и на компоненты вне строки. В следующем примере компонент TitlePage.qml создаёт два экземпляра TitleText. Несмотря на то, что тип TitleText находится в отдельном файле, он всё ещё имеет доступ к свойству title при использовании внутри TitlePage. QML — это язык с динамической областью видимости — в зависимости от того, где он используется, свойство title может разрешаться по-разному.

// TitlePage.qml
import QtQuick 2.0
Item {
    property string title

    TitleText {
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property int size
    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

Динамическая область видимости очень мощна, но ею нужно пользоваться осторожно, чтобы поведение QML-кода не стало трудно предсказуемым. Как правило, её следует использовать только в тех случаях, когда два компонента уже тесно связаны каким-то другим способом. При создании многократно используемых компонентов предпочтительнее использовать интерфейсы свойств, как в этом:

// TitlePage.qml
import QtQuick 2.0
Item {
    id: root
    property string title

    TitleText {
        title: root.title
        size: 22
        anchors.top: parent.top
    }

    TitleText {
        title: root.title
        size: 18
        anchors.bottom: parent.bottom
    }
}

// TitleText.qml
import QtQuick 2.0
Text {
    property string title
    property int size

    text: "<b>" + title + "</b>"
    font.pixelSize: size
}

Переопределённые свойства

QML позволяет именам свойств, определённым в объявлении объекта, быть переопределёнными свойствами, объявленными в другом объявлении объекта, которое расширяет первый. Например:

// Displayable.qml
import QtQuick 2.0
Item {
    property string title
    property string detail

    Text {
        text: "<b>" + title + "</b><br>" + detail
    }

    function getTitle() { return title }
    function setTitle(newTitle) { title = newTitle }
}

// Person.qml
import QtQuick 2.0
Displayable {
    property string title
    property string firstName
    property string lastName

    function fullName()  { return title + " " + firstName + " " + lastName }
}

Здесь имя title присвоено как заголовку выходного текста для Displayable, так и почетному титулу объекта Person.

Переопределённое свойство разрешается в соответствии с областью видимости, в которой оно упоминается. Внутри области видимости компонента Person или из внешней области видимости, которая ссылается на экземпляр компонента Person, title разрешается на свойство, объявленное внутри Person.qml. Функция fullName будет ссылаться на свойство title , объявленное внутри Person.

Однако внутри компонента Displayable title относится к свойству, объявленному в Displayable.qml. Функции getTitle() и setTitle(), а также связывание свойства text объекта Text будут относиться к свойству title , объявленному в компоненте Displayable.

Несмотря на одинаковое имя, два свойства полностью независимы. Обработчик сигнала onChanged для одного из свойств не будет срабатывать при изменении другого свойства с тем же именем. Псевдоним для любого из свойств будет ссылаться на одно или другое, но не на оба одновременно.

Объект глобальной области видимости JavaScript

QML запрещает имена типов, идентификаторов и свойств, которые конфликтуют со свойствами глобального объекта, чтобы избежать путаницы. Программисты могут быть уверены, что Math.min(10, 9) всегда будет работать как ожидается!

Дополнительную информацию см. в разделе JavaScript Host Environment.

© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-6.1/qtqml-documents-scope.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API