Область видимости и разрешение имен
Связывания свойств 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-5.9/qtqml-documents-scope.html