Spec-Zone.ru › Qt 6.0

Область видимости и разрешение имен

Связывания свойств 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). Например, в маловероятном случае, если объект области видимости привязки имел свойство 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.0/qtqml-documents-scope.html

Spec-Zone.ru

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