Spec-Zone.ru › Qt

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

Связывания свойств 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
}

Связывания имеют доступ к свойствам объекта области видимости без квалификации. В предыдущем примере связывание получает доступ к свойству parent объекта Item напрямую, без необходимости любого префикса объекта. 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.2/qtqml-documents-scope.html

Spec-Zone.ru

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