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 MouseArea. Это отношение описывается с помощью условного выражения:
import QtQuick 2.0
Rectangle {
id: colorbutton
width: 200; height: 80;
color: mousearea.pressed ? "steelblue" : "lightsteelblue"
MouseArea {
id: mousearea
anchors.fill: parent
}
} Фактически, в определении связи свойств может быть использовано любое выражение JavaScript (насколько бы оно ни было сложным), если результат выражения является значением, тип которого может быть присвоен свойству. Это включает побочные эффекты. Однако сложные связи и побочные эффекты не рекомендуются, так как они могут снизить производительность, читаемость и поддерживаемость кода.
Существует два способа определения связи свойств: первый (и наиболее распространённый) - это, как показано выше, в инициализации свойства. Второй (и гораздо менее распространённый) способ - присвоить свойству функцию, возвращённую функцией Qt.binding(), из императивного кода JavaScript, как показано ниже:
import QtQuick 2.0
Rectangle {
id: colorbutton
width: 200; height: 80;
color: "red"
MouseArea {
id: mousearea
anchors.fill: parent
}
Component.onCompleted: {
color = Qt.binding(function() { return mousearea.pressed ? "steelblue" : "lightsteelblue" });
}
} Дополнительную информацию о том, как определять связи свойств, см. в документации по связям свойств, а информацию о различии связей и присваивания значений свойств см. в документации по присваиванию свойств по сравнению с связями свойств.
JavaScript в обработчиках сигналов
Типы объектов QML могут отправлять сигналы в ответ на определённые события. Эти сигналы могут обрабатываться функциями-обработчиками сигналов, которые могут быть определены клиентами для реализации пользовательской логики программы.
Предположим, что кнопка, представленная типом Rectangle, имеет MouseArea и метку Text. MouseArea отправит свой сигнал pressed при нажатии пользователем определённой интерактивной области, что автоматически вызовет обработчик onPressed, который может быть определён клиентами. Движок QML выполнит выражения JavaScript, определённые в обработчиках onPressed и onReleased, по мере необходимости. Как правило, обработчик сигнала связан с выражениями JavaScript для инициирования других событий или просто для присваивания значений свойств.
import QtQuick 2.0
Rectangle {
id: button
width: 200; height: 80; color: "lightsteelblue"
MouseArea {
id: mousearea
anchors.fill: parent
onPressed: {
// arbitrary JavaScript expression
label.text = "I am Pressed!"
}
onReleased: {
// arbitrary JavaScript expression
label.text = "Click Me!"
}
}
Text {
id: label
anchors.centerIn: parent
text: "Press Me!"
}
} Подробную информацию о сигналах и обработчиках сигналов см. в документации по системе сигналов и обработчиков событий, а подробную информацию о том, как определить реализацию обработчиков сигналов в QML с JavaScript, см. в документации по атрибутам объекта QML.
JavaScript в автономных функциях
Логика программы также может быть определена в функциях JavaScript. Эти функции могут быть определены непосредственно в документах QML (как пользовательские методы) или внешне в импортированных файлах JavaScript.
JavaScript в пользовательских методах объекта
Пользовательские методы могут быть определены в документах QML и могут вызываться из обработчиков сигналов, связей свойств или функций в других объектах QML. Методы, определённые таким образом, часто называются встроенными функциями JavaScript, потому что их реализация включена в определение типа QML-объекта (документ QML), а не во внешнем файле JavaScript.
Пример встроенного пользовательского метода:
import QtQuick 2.0
Item {
function factorial(a) {
a = parseInt(a);
if (a <= 0)
return 1;
else
return a * factorial(a - 1);
}
MouseArea {
anchors.fill: parent
onClicked: console.log(factorial(10))
}
} Функция factorial будет выполняться всякий раз, когда MouseArea обнаружит сигнал clicked.
Важно, что пользовательские методы, определённые непосредственно в документе QML, доступны другим объектам, и поэтому встроенные функции в корневом объекте компонента QML могут вызываться вызывающими сторонами за пределами компонента. Если этого не нужно, метод можно добавить к объекту, не являющемуся корневым, или, что предпочтительнее, написать во внешнем файле JavaScript.
Подробную информацию о том, как определять пользовательские методы в QML с реализацией кода JavaScript, см. в документации по атрибутам объекта QML.
Функции в импортированных файлах JavaScript
Нетривиальная логика программы лучше всего отделяется во внешние файлы JavaScript. Эти файлы можно импортировать в файлы QML с помощью инструкции import, аналогично тому, как импортируются модули.
Например, метод factorial() в вышеприведённом примере можно перенести во внешний файл с именем factorial.js, и получить доступ к нему так:
import "factorial.js" as MathFunctions
Item {
MouseArea {
anchors.fill: parent
onClicked: console.log(MathFunctions.factorial(10))
}
} Дополнительную информацию о загрузке внешних файлов JavaScript в QML см. в разделе о импорте ресурсов JavaScript в QML.
Подключение сигналов к функциям JavaScript
Типы объектов QML, которые отправляют сигналы, также предоставляют обработчики сигналов по умолчанию для своих сигналов, как описано в предыдущем разделе. Однако иногда клиент хочет, чтобы сигнал, отправленный одним объектом, вызывал функцию, определённую в другом объекте; и в этом случае подключение сигнала часто предпочтительнее.
Сигнал, отправленный объектом QML, может быть подключён к функции JavaScript, вызвав метод connect() сигнала и передав функцию JavaScript в качестве аргумента. Например, следующий код подключает сигнал MouseArea clicked к функции jsFunction() в script.js.
import QtQuick 2.0
import "script.js" as MyScript
Item {
id: item
width: 200; height: 200
MouseArea {
id: mouseArea
anchors.fill: parent
}
Component.onCompleted: {
mouseArea.clicked.connect(MyScript.jsFunction)
}
} |
// script.js
function jsFunction() {
console.log("Called JavaScript function!")
} |
Функция jsFunction() теперь будет вызываться всякий раз, когда сигнал clicked MouseArea отправляется.
Дополнительную информацию см. в Подключение сигналов к методам и сигналам.
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.9/qtqml-javascript-expressions.html