QML文書におけるJavaScript表現

QMLが提供するJavaScriptホスト環境では、条件演算子、配列、変数設定、ループなどの標準的なJavaScriptを実行することができます。標準的なJavaScriptのプロパティに加え、QMLグローバルオブジェクトには、UIの構築やQML環境とのやりとりを簡単にするためのヘルパーメソッドが多数用意されています。

QMLが提供するJavaScript環境は、Webブラウザの環境よりも厳しいものです。例えば、QMLではJavaScriptのグローバルオブジェクトのメンバを追加したり、変更したりすることはできません。通常のJavaScriptでは、変数を宣言せずに使用することで、誤ってこのようなことをしてしまう可能性があります。QMLでは例外が発生しますので、ローカル変数はすべて明示的に宣言しなければなりません。QMLから実行されるJavaScriptコードの制限については、JavaScript環境の制限を参照してください。

QML文書のさまざまな部分にJavaScriptのコードを記述することができます:

  1. プロパティバインディングのボディ。プロパティバインディングのボディ。これらの JavaScript 式は QML オブジェクトのプロパティ間の関係を記述します。プロパティの依存関係が変更されると、指定された関係に従ってプロパティも自動的に更新されます。
  2. シグナルハンドラの本体。これらの JavaScript 記述は、QML オブジェクトが関連するシグナルを発するたびに自動的に評価されます。
  3. カスタムメソッドの定義。QML オブジェクトのボディ内で定義された JavaScript 関数は、そのオブジェクトのメソッドとなります。
  4. スタンドアロンJavaScriptリソース(.js)ファイル。これらのファイルは実際にはQML文書とは別のものですが、QML文書に取り込むことができます。インポートされたファイル内で定義された関数や変数は、プロパティバインディング、 シグナルハンドラ、カスタムメソッドで使用することができます。

プロパティバインディングにおけるJavaScript

次の例では、Rectanglecolor プロパティが、TapHandlerpressed プロパティに依存しています。この関係は条件式を使って記述されています:

import QtQuick 2.12

Rectangle {
    id: colorbutton
    width: 200; height: 80;

    color: inputHandler.pressed ? "steelblue" : "lightsteelblue"

    TapHandler {
        id: inputHandler
    }
}

実際には、プロパテ ィ バ イ ンデ ィ ン グ定義では、式の結果がプ ロ パテ ィ に割 り 当て ら れ る 型の値であ る 限 り 、 ど の よ う な複雑な JavaScript 式で も 使用で き ます。これには副作用も含まれます。しかし、複雑なバインディングや副作用は、コードのパフォーマンスや可読性、保守性を低下させる可能性があるため、推奨されません。

プロパティ・バインディングを定義する方法は2つあります。最も一般的なものは、先の例で示したプロパティの初期化です。2番目の(そしてはるかにまれな)方法は、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ラベルがあるとします。ユーザーがボタンを押すと、TapHandlertapped シグナルを発する。クライアントは、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))
    }
}

TapHandlertapped シグナルを発するたびに fibonacci 関数が実行されます。

注意: QMLドキュメント内でインライン定義されたカスタムメソッドは、 他のオブジェクトに公開されます。従って、QMLコンポーネントのルートオブジェクトのインライン関数は、 コンポーネント外の呼び出し元から呼び出される可能性があります。そのため、QML コンポーネントのルートオブジェクトのインライン関数は、 コンポーネントの外部からの呼び出しによって呼び出される可能性があります。 これを望まない場合は、メソッドをルートオブジェクト以外のオブジェクトに追加するか、 できれば外部の JavaScript ファイルに記述してください。

JavaScriptを使ったQMLのカスタムメソッドの定義については、QML Object Attributesdocumentationを参照してください。

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に読み込む方法については、「QMLでJavaScriptリソースをインポートする」を参照してください。

シグナルとJavaScript関数の接続

前節で説明したように、シグナルを発するQMLのオブジェクトタイプは、そのシグナ ルに対してデフォルトのシグナルハンドラを提供します。しかし時には、別のQMLオブジェクトがシグナルを発したときに、 そのQMLオブジェクトで定義された関数を起動させたいと考えることもあります。そのような場合はシグナル接続を使うことができます。

QML オブジェクトが発するシグナルを JavaScript の関数に接続するには、 シグナルのconnect() メソッドを呼び出し、JavaScript の関数を引数として渡します。例えば、次のコードはTapHandlertapped シグナルをscript.jsjsFunction() に接続しています:

import QtQuick
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!")
}

TapHandlertapped シグナルが発信されるたびにjsFunction() が呼び出されます。

詳しくは、シグナルをメソッドやシグナルに接続するを参照してください。

アプリケーションの起動コードにおけるJavaScript

アプリケーション(またはコンポーネントのインスタンス)の起動時に、命令的なコードを実行する必要があることがあります。起動スクリプトを外部のスクリプトファイルにグローバルコードとして記述するのは魅力的ですが、QMLの環境が完全に確立されていない可能性があるため、これには大きな制限があります。例えば、オブジェクトが作成されていなかったり、プロパティのバインディングが確立されていなかったりします。グローバルスクリプトコードの正確な制限についてはJavaScript Environment Restrictionsを参照してください。

QML オブジェクトは、インスタンス化が完了するとComponent.completed attached シグナルを発行します。対応するComponent.onCompleted ハンドラの JavaScript コードは、オブジェクトがインスタンス化された後に実行されます。したがって、アプリケーションの起動コードを記述するのに最適な場所は、トップレベルオブジェクトのComponent.onCompleted ハンドラです。なぜなら、このオブジェクトは QML 環境が完全に確立したときにComponent.completed を発するからです。

なぜなら、このオブジェクトはQML環境が完全に確立されたときに を発するからです:

import QtQuick 2.0

Rectangle {
    function startupFunction() {
        // ... startup code
    }

    Component.onCompleted: startupFunction();
}

ネストされたオブジェクトやネストされたQMLコンポーネントのインスタンスも含め、QMLファイル内のどのオブジェクトでも、このアタッチされたプロパティを使うことができます。起動時に実行されるonCompleted() ハンドラが複数ある場合、それらは未定義の順序で順次実行されます。

同様に、すべてのComponent は、破棄される直前にdestruction() シグナルを発します。

本ドキュメントに含まれる文書の著作権は、それぞれの所有者に帰属します。 本書で提供されるドキュメントは、Free Software Foundation が発行したGNU Free Documentation License version 1.3に基づいてライセンスされています。 Qtおよびそれぞれのロゴは、フィンランドおよびその他の国におけるThe Qt Company Ltd.の 商標です。その他すべての商標は、それぞれの所有者に帰属します。