Выражения JavaScript в документах QML

Добавлено 10 мая 2022 в 21:23

Хост-среда JavaScript, предоставляемая QML, может запускать допустимые стандартные конструкции JavaScript, такие как условные операторы, массивы, установки переменных и циклы. В дополнение к стандартным свойствам JavaScript глобальный объект QML включает в себя ряд вспомогательных методов, которые упрощают создание пользовательских интерфейсов и взаимодействие со средой QML.

Среда JavaScript, предоставляемая QML, более строгая, чем в веб-браузере. Например, в QML нельзя добавлять или изменять члены глобального объекта JavaScript. В обычном JavaScript это можно сделать случайно, используя переменную без ее объявления. В QML это вызовет исключение, поэтому все локальные переменные должны быть объявлены явно. Полное описание ограничений на код JavaScript, выполняемый из QML, смотрите в разделе «Ограничения среды JavaScript».

Код JavaScript могут содержать различные части документов QML:

  1. Тело привязок свойств. Эти выражения JavaScript описывают связи между свойствами объектов QML. Когда зависимости свойства изменяются, свойство также автоматически обновляется в соответствии с указанной связью.
  2. Тело обработчиков сигналов. Эти инструкции JavaScript автоматически вычисляются всякий раз, когда объект QML выдает соответствующий сигнал.
  3. Определение пользовательских методов. Функции JavaScript, определенные в теле объекта QML, становятся методами этого объекта.
  4. Отдельные (.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().

Теги

GUI / Графический интерфейс пользователяJavaScriptQMLQtQtQuickПрограммирование

На сайте работает сервис комментирования DISQUS, который позволяет вам оставлять комментарии на множестве сайтов, имея лишь один аккаунт на Disqus.com.

В случае комментирования в качестве гостя (без регистрации на disqus.com) для публикации комментария требуется время на премодерацию.