Область видимости и разрешение имён
Связывания свойств 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 включают инструкции import, которые определяют имена типов и 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/archives/qt-5.11/qtqml-documents-scope.html