Выражения JavaScript в документах QML
Хост-среда JavaScript, предоставляемая QML, может запускать допустимые стандартные конструкции JavaScript, такие как условные операторы, массивы, установки переменных и циклы. В дополнение к стандартным свойствам JavaScript глобальный объект QML включает в себя ряд вспомогательных методов, которые упрощают создание пользовательских интерфейсов и взаимодействие со средой QML.
Среда JavaScript, предоставляемая QML, более строгая, чем в веб-браузере. Например, в QML нельзя добавлять или изменять члены глобального объекта JavaScript. В обычном JavaScript это можно сделать случайно, используя переменную без ее объявления. В QML это вызовет исключение, поэтому все локальные переменные должны быть объявлены явно. Полное описание ограничений на код JavaScript, выполняемый из QML, смотрите в разделе «Ограничения среды JavaScript».
Код JavaScript могут содержать различные части документов QML:
- Тело привязок свойств. Эти выражения JavaScript описывают связи между свойствами объектов QML. Когда зависимости свойства изменяются, свойство также автоматически обновляется в соответствии с указанной связью.
- Тело обработчиков сигналов. Эти инструкции JavaScript автоматически вычисляются всякий раз, когда объект QML выдает соответствующий сигнал.
- Определение пользовательских методов. Функции JavaScript, определенные в теле объекта QML, становятся методами этого объекта.
- Отдельные (.js) файлы ресурсов JavaScript. Эти файлы фактически отделены от документов QML, но их можно импортировать в документы QML. Функции и переменные, определенные в импортированных файлах, можно использовать в привязках свойств, обработчиках сигналов и пользовательских методах.
JavaScript в привязках свойств
В следующем примере свойство color
элемента Rectangle
зависит от свойства pressed
в TapHandler
. Эта связь описывается с помощью условного выражения:
import QtQuick 2.12
Rectangle {
id: colorbutton
width: 200; height: 80;
color: inputHandler.pressed ? "steelblue" : "lightsteelblue"
TapHandler {
id: inputHandler
}
}
Фактически любое выражение JavaScript (независимо от его сложности) может использоваться в определении привязки свойства, если результатом этого выражения является значение, тип которого может быть присвоен свойству. Это включает побочные эффекты. Однако сложные привязки и побочные эффекты не рекомендуются, поскольку они могут снизить производительность, читабельность и поддерживаемость кода.
Есть два способа определить привязку свойства: наиболее распространенный из них показан в примере выше, при инициализации свойства. Второй (и гораздо более редкий) способ – присвоить свойству функцию, возвращаемую функцией Qt.binding()
, из императивного кода JavaScript, как показано ниже:
import QtQuick 2.12
Rectangle {
id: colorbutton
width: 200; height: 80;
color: "red"
TapHandler {
id: inputHandler
}
Component.onCompleted: {
color = Qt.binding(function() { return inputHandler.pressed ? "steelblue" : "lightsteelblue" });
}
}
Дополнительную информацию о том, как определить привязки свойств, смотрите в разделе о привязках свойств, а сведения о том, чем привязки отличаются от присвоений значений, смотрите в разделе «Создание привязок свойств из JavaScript».
JavaScript в обработчиках сигналов
Типы объектов QML могут генерировать сигналы в ответ на определенные события. Эти сигналы могут обрабатываться функциями обработчиков сигналов, которые могут быть определены клиентами для реализации пользовательской программной логики.
Предположим, что кнопка, представленная типом Rectangle
, имеет TapHandler
и метку Text
. TapHandler
генерирует сигнал tapped
, когда пользователь нажимает кнопку. Клиенты могут реагировать на сигнал в обработчике onTapped
, используя выражения JavaScript. Механизм QML выполняет эти выражения JavaScript, определенные в обработчике, по мере необходимости. Обычно обработчик сигналов привязывается к выражениям JavaScript, чтобы инициировать другие события или присвоивать значения свойств.
import QtQuick 2.12
Rectangle {
id: button
width: 200; height: 80; color: "lightsteelblue"
TapHandler {
id: inputHandler
onTapped: {
// произвольное выражение JavaScript
console.log("Tapped!")
}
}
Text {
id: label
anchors.centerIn: parent
text: inputHandler.pressed ? "Pressed!" : "Press here!"
}
}
Дополнительную информацию о сигналах и обработчиках сигналов смотрите в следующих разделах:
JavaScript в автономных функциях
Логика программы также может быть определена в функциях JavaScript. Эти функции могут быть определены как встроенные в документы QML (как пользовательские методы) или как внешние в импортированных файлах JavaScript.
JavaScript в пользовательских методах
Пользовательские методы могут быть определены в документах QML и могут вызываться из обработчиков сигналов, привязок свойств или функций в других объектах QML. Такие методы часто называют встроенными функциями JavaScript, поскольку их реализация включена в определение типа объекта QML (в документ QML), а не во внешний файл JavaScript.
Пример встроенного пользовательского метода выглядит следующим образом:
import QtQuick 2.12
Item {
function fibonacci(n){
var arr = [0, 1];
for (var i = 2; i < n + 1; i++)
arr.push(arr[i - 2] + arr[i -1]);
return arr;
}
TapHandler {
onTapped: console.log(fibonacci(10))
}
}
Функция fibonacci
запускается всякий раз, когда TapHandler
выдает сигнал tapped
.
Примечание. Пользовательские методы, определенные как встроенные в документ QML, доступны другим объектам, поэтому встроенные функции корневого объекта в компоненте QML могут вызываться вызывающими объектами вне компонента. Если это нежелательно, метод можно добавить к некорневому объекту или, что предпочтительнее, записать во внешний файл JavaScript.
Дополнительную информацию об определении пользовательских методов в QML с использованием JavaScript смотрите в разделе об атрибутах объектов QML.
Функции, определенные в файле JavaScript
Нетривиальную программную логику лучше всего вынести в отдельный файл JavaScript. Этот файл можно импортировать в QML с помощью инструкции import
, как и модули QML.
Например, метод fibonacci()
из предыдущего примера можно переместить во внешний файл с именем fib.js
и получить к нему доступ следующим образом:
import QtQuick 2.12
import "fib.js" as MathFunctions
Item {
TapHandler {
onTapped: console.log(MathFunctions.fibonacci(10))
}
}
Дополнительную информацию о загрузке внешних файлов JavaScript в QML смотрите в разделе «Импорт ресурсов JavaScript в QML».
Подключение сигналов к функциям JavaScript
Типы объектов QML, которые генерируют сигналы, также предоставляют обработчики сигналов по умолчанию, как описано в предыдущем разделе. Однако иногда клиент хочет вызвать функцию, определенную в объекте QML, когда другой объект QML выдает сигнал. Такие сценарии могут быть обработаны соединением сигналов.
Сигнал, выдаваемый объектом QML, можно подключить к функции JavaScript, вызвав метод сигнала connect()
и передав функцию JavaScript в качестве аргумента. Например, следующий код соединяет сигнал tapped TapHandler
с функцией jsFunction()
в script.js:
// script.js
function jsFunction() {
console.log("Called JavaScript function!")
}
import QtQuick 2.12
import "script.js" as MyScript
Item {
id: item
width: 200; height: 200
TapHandler {
id: inputHandler
}
Component.onCompleted: {
inputHandler.tapped.connect(MyScript.jsFunction)
}
}
jsFunction()
вызывается всякий раз, когда выдается сигнал tapped TapHandler
.
Для получения дополнительной информации смотрите раздел «Подключение сигналов к методам и сигналам».
JavaScript в коде запуска приложения
Иногда при запуске приложения (или экземпляра компонента) необходимо запустить некоторый императивный код. Хотя заманчиво просто включить скрипт запуска в качестве глобального кода во внешний файл скрипта, это может иметь серьезные ограничения, поскольку среда QML может быть установлена не полностью. Например, некоторые объекты могут быть не созданы или не установлены привязки некоторых свойств. Точные ограничения кода глобального скрипта смотрите в разделе «Ограничения среды JavaScript».
Объект QML выдает прикрепленный сигналComponent.completed
, когда его создание завершено. Код JavaScript в соответствующем обработчике Component.onCompleted
запускается после создания экземпляра объекта. Таким образом, код, который необходимо выполнить после запуска приложения, лучше всего писать в обработчике Component.onCompleted
объекта верхнего уровня, поскольку этот объект выдает Component.completed
, когда среда QML полностью установлена.
Например:
import QtQuick 2.0
Rectangle {
function startupFunction() {
// ... код запуска
}
Component.onCompleted: startupFunction();
}
Любой объект в файле QML, включая вложенные объекты и экземпляры вложенных компонентов QML, может использовать это присоединенное свойство. Если при запуске выполняется более одного обработчика onCompleted()
, они запускаются последовательно в неопределенном порядке.
Точно так же каждый Component
непосредственно перед уничтожением генерирует сигнал destruction()
.