Область видимости и разрешение имён
Связывания свойств 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 свойству a объекта QML.
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-среде выполнения.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.14/qtqml-documents-scope.html