JavaScript-выражения в документах QML
Окружение JavaScript, предоставляемое QML, может выполнять стандартные конструкции JavaScript, такие как условные операторы, массивы, установка переменных и циклы. Помимо стандартных свойств JavaScript, объект QML Global Object включает ряд вспомогательных методов, упрощающих создание пользовательских интерфейсов и взаимодействие с окружением QML.
Окружение JavaScript, предоставляемое QML, более строгое, чем в веб-браузере. Например, в QML нельзя добавлять или изменять члены глобального объекта JavaScript. В обычном JavaScript это можно сделать случайно, используя переменную без её объявления. В QML это вызовет исключение, поэтому все локальные переменные должны быть явно объявлены. Полное описание ограничений кода JavaScript, выполняемого из QML, см. в разделе Ограничения среды JavaScript.
Разные части документов QML могут содержать код JavaScript:
- Тело связей свойств. Эти выражения JavaScript описывают отношения между свойствами QML-объектов свойств. При изменении зависимостей свойства оно также автоматически обновляется в соответствии с указанным отношением.
- Тело обработчиков сигналов. Эти операторы JavaScript автоматически оцениваются всякий раз, когда QML-объект излучает соответствующий сигнал.
- Определение пользовательских методов. Функции JavaScript, определённые в теле QML-объекта, становятся методами этого объекта.
- Самостоятельные файлы ресурсов JavaScript (.js). Эти файлы фактически отделены от документов QML, но их можно импортировать в документы QML. Функции и переменные, определённые в импортированных файлах, могут использоваться в связях свойств, обработчиках сигналов и пользовательских методах.
JavaScript в связях свойств
В следующем примере свойство color прямоугольника зависит от свойства pressed обработчика нажатий. Это отношение описывается с помощью условного выражения:
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, имеет обработчик нажатий и метку Text. Обработчик нажатий излучает сигнал 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 выполняется всякий раз, когда обработчик нажатий излучает сигнал 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 обработчика нажатий к функции 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 обработчика нажатий.
Дополнительную информацию см. в разделе Подключение сигналов к методам и сигналам.
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.12/qtqml-javascript-expressions.html