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