プロパティのバインディング

オブジェクトのプロパティには静的な値を割り当てることができます。しかし、QMLに組み込まれている動的なオブジェクトの振る舞いを最大限に利用するために、ほとんどのQMLオブジェクトはプロパティバインディングを利用しています。

プロパティ・バインディングはQMLの中核的な機能で、開発者は異なるオブジェクトのプロパティ間の関係を指定することができます。プロパティの依存関係の値が変化すると、指定された関係に従ってプロパティが自動的に更新されます。

舞台裏では、QMLエンジンがプロパティの依存関係(つまり、バインディング式の変数)を監視しています。変更が検出されると、QMLエンジンはバインディング式を再評価し、新しい結果をプロパティに適用します。

概要

プロパティのバインディングを作成するには、プロパティに JavaScript の式を代入します。最も単純なバインディングは、他のプロパティへの参照です。次の例では、青いRectangle の height が親の height にバインドされています:

Rectangle {
    width: 200; height: 200

    Rectangle {
        width: 100
        height: parent.height
        color: "blue"
    }
}

親の矩形の高さが変わるたびに、青い矩形の高さは自動的に同じ値に更新されます。

QMLは標準に準拠したJavaScriptエンジンを使用しているため、バインディングには有効なJavaScriptの式や文を記述することができます。バインディングはオブジェクトのプロパティにアクセスしたり、メソッドを呼び出したり、DateMath のような JavaScript 組み込みのオブジェクトを使用することができます。以下は、先ほどの例で考えられる他のバインディングです:

height: parent.height / 2

height: Math.min(parent.width, parent.height)

height: parent.height > 100 ? parent.height : parent.height/2

height: {
    if (parent.height > 100)
        return parent.height
    else
        return parent.height / 2
}

height: someMethodThatReturnsHeight()

以下は、より多くのオブジェクトや型を含む、より複雑な例です:

Column {
    id: column
    width: 200
    height: 200

    Rectangle {
        id: topRect
        width: Math.max(bottomRect.width, parent.width/2)
        height: (parent.height / 3) + 10
        color: "yellow"

        TextInput {
            id: myTextInput
            text: "Hello QML!"
        }
    }

    Rectangle {
        id: bottomRect
        width: 100
        height: 50
        color: myTextInput.text.length <= 10 ? "red" : "blue"
    }
}

前の例では

  • topRect.width bottomRect.width に依存しcolumn.width
  • topRect.height に依存しています。column.height
  • bottomRect.color に依存している。myTextInput.text.length

さ ら に、 それ自体がバ イ ンデ ィ ン グ と し て用い ら れてい る JavaScript 関数内で参照 さ れてい る すべてのプ ロ パテ ィ は、 再評価 さ れます。たとえば、以下のスニペットでは、Rectangleenabled プロパティが変更されるたびに、xy プロパティのバインディングが再評価されます:

Rectangle {
    x: rectPosition()
    y: rectPosition()
    width: 200
    height: 200
    color: "lightblue"

    function rectPosition() {
        return enabled ? 0 : 100
    }
}

構文上、バインディングは任意の複雑さを持つことが許されています。しかし、バインディングが過度に複雑な場合(複数行にわたったり、命令的なループを含むなど)、そのバインディングがプロパティの関係を記述する以上の目的で使用されている可能性があります。複雑なバインディングは、コードのパフォーマンスや可読性、保守性を低下させる可能性があります。複雑なバインディングを持つコンポーネントの設計をやり直すか、少なくともバインディングを別の関数にまとめるのがよいでしょう。一般的なルールとして、ユーザーはバインディングの評価順序に依存すべきではありません。

JavaScriptからプロパティ・バインディングを作成する

バインディングを持つプロパティは、必要に応じて自動的に更新されます。しかし、後にJavaScriptステートメントからプロパティに静的値が割り当てられると、バインディングは削除されます。

例えば、以下のRectangle は、最初はそのheight が常にそのwidth の2倍であることを保証しています。しかし、スペースキーが押されると、width*3 の現在の値が静的値としてheight に割り当てられます。その後、 width が変更されても、height はこの値に固定される。静的値の割り当てにより、バインディングは解除されます。

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = width * 3
    }
}

矩形に固定の高さを与え、自動更新を停止することを意図しているのであれば、これは問題ではありません。しかし、widthheight の間に新しい関係を確立することを意図している場合は、新しいバインディング式を Qt.binding() 関数でラップする必要があります:

import QtQuick 2.0

Rectangle {
    width: 100
    height: width * 2

    focus: true
    Keys.onSpacePressed: {
        height = Qt.binding(function() { return width * 3 })
    }
}

これで、スペースキーが押された後、矩形の高さは常に幅の3倍になるように自動更新され続けます。

バインディングの上書きのデバッグ

QMLアプリケーションでよくあるバグの原因は、JavaScript文の静的な値を誤ってバインディングに上書きしてしまうことです。開発者がこの種の問題を追跡しやすくするために、QMLエンジンは命令的な代入によってバインディングが失われたときにメッセージを発するようになっています。

このようなメッセージを生成するには、qt.qml.binding.removal のロギングカテゴリで情報出力を有効にする必要があります:

QLoggingCategory::setFilterRules(QStringLiteral("qt.qml.binding.removal.info=true"));

ロギングカテゴリからの出力を有効にする方法についてはQLoggingCategory のドキュメントを参照してください。

なお、バインディングを上書きすることは状況によってはまったく問題ありません。QMLエンジンによって生成されたメッセージは診断の補助として扱われるべきであり、 さらなる調査を行わずに問題の証拠とする必要はありません。

this 、プロパティバインディングを使用する

JavaScript からプロパティバインディングを作成する場合、this キーワードを使用することで、バインディングを受け取るオブジェクトを参照することができます。これはプロパティ名の曖昧さを解決するのに役立ちます。

た と えば、 以下のComponent.onCompleted ハン ド ラ はItem の ス コ ープ内で定義 さ れてい ます。 こ の ス コ ープでは、widthItem の width を指 し ますが、Rectangle の width ではあ り ません。Rectangleheight を自身のwidth にバイン ド する には、 バ イ ンデ ィ ン グ式で明示的にthis.width (あ るいはrect.width ) を参照す る 必要があ り ます:

Item {
    width: 500
    height: 500

    Rectangle {
        id: rect
        width: 100
        color: "yellow"
    }

    Component.onCompleted: {
        rect.height = Qt.binding(function() { return this.width * 2 })
        console.log("rect.height = " + rect.height) // prints 200, not 1000
    }
}

注: this の値は、プロパティ・バインディング以外では定義されません。詳 し く は 「JavaScript 環境の制限」 を参照 し て く だ さ い。

アンカーによる位置決め」も参照してください

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