JavaScript-выражения в документах QML
Окружение JavaScript, предоставляемое QML, может выполнять допустимые стандартные конструкции JavaScript, такие как условные операторы, массивы, присвоение переменных и циклы. Помимо стандартных свойств JavaScript, объект QML Global включает ряд вспомогательных методов, которые упрощают создание пользовательских интерфейсов и взаимодействие с окружением QML.
Окружение JavaScript, предоставляемое QML, более строгое, чем в веб-браузере. Например, в QML нельзя добавлять или изменять члены глобального объекта JavaScript. В обычном JavaScript это можно сделать случайно, используя переменную без её объявления. В QML это вызовет исключение, поэтому все локальные переменные должны быть явно объявлены. Полное описание ограничений кода JavaScript, выполняемого из QML, см. в разделе Ограничения среды JavaScript.
Различные части документов QML могут содержать код JavaScript:
- Тело связываний свойств. Эти выражения JavaScript описывают взаимосвязи между свойствами QML-объекта свойств. При изменении зависимостей свойства оно также автоматически обновляется в соответствии с указанной взаимосвязью.
- Тело обработчиков сигналов. Эти операторы JavaScript автоматически вычисляются всякий раз, когда QML-объект испускает соответствующий сигнал.
- Определение пользовательских методов. Функции JavaScript, определенные в теле QML-объекта, становятся методами этого объекта.
- Самостоятельные файлы JavaScript-ресурсов (.js). Эти файлы фактически отделены от 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 в обработчиках сигналов
Типы 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: {
// arbitrary JavaScript expression
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 Object Attributes.
Функции, определенные в файле 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.
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)
}
} |
// script.js
function jsFunction() {
console.log("Called JavaScript function!")
} |
Функция jsFunction() вызывается всякий раз, когда сигнал tapped объекта TapHandler испускается.
Дополнительную информацию см. в разделе Подключение сигналов к методам и сигналам.
JavaScript в коде запуска приложения
Иногда необходимо запустить некоторый императивный код при запуске приложения (или экземпляра компонента). Хотя заманчиво просто включить скрипт запуска как глобальный код во внешний файл скрипта, это может иметь серьёзные ограничения, так как QML-окружение может быть не полностью установлено. Например, некоторые объекты могут не быть созданы, или некоторые связывания свойств могут не быть установлены. См. Ограничения среды JavaScript для точного описания ограничений глобального кода скрипта.
QML-объект испускает сигнал Component.completed attached при завершении его создания. JavaScript-код в соответствующем обработчике Component.onCompleted выполняется после создания объекта. Таким образом, лучшим местом для написания кода запуска приложения является обработчик Component.onCompleted верхнего уровня, потому что этот объект испускает Component.completed при полном установлении QML-окружения.
Например:
import QtQuick 2.0
Rectangle {
function startupFunction() {
// ... startup code
}
Component.onCompleted: startupFunction();
} Любой объект в файле QML - включая вложенные объекты и вложенные экземпляры QML-компонентов - может использовать это присоединенное свойство. Если существует более одного обработчика onCompleted() для выполнения при запуске, они выполняются последовательно в неопределенном порядке.
Точно так же каждый Component испускает сигнал destruction() непосредственно перед уничтожением.
© The Qt Company Ltd
Licensed under the GNU Free Documentation License, Version 1.3.
https://doc.qt.io/qt-5.15/qtqml-javascript-expressions.html