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 прямоугольника зависит от свойства 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-6.2/qtqml-javascript-expressions.html