バインディング

前回示したプログラムをもう一度。

import javafx.ui.*;

var message:String = "Hello, World!";

Frame {
    title: "Binding Sample"
    width: 200
    height: 100
    visible: true

    content: Label {
        text: message
    }
}

ここで message を後から変更すると、表示にも反映されるでしょうか?
つまり......

import javafx.ui.*;

var message:String = "Hello, World!";

Frame {
    title: "Binding Sample"
    width: 200
    height: 100
    visible: true

    content: Label {
        text: message
    }
}

message = "こんにちは世界!";

とすると、表示がラベルの文字列が「こんにちは世界!」に変更されるかどうかということです。

さっそく、やってみると......

f:id:skrb:20080106030806p:image

なにも変わりません orz

これはどういうことなんでしょう?

どうやら、イニシャライザでの text: message というのは、値渡しのようです。参照渡しではないので message 変数が変化しようとも Frame の text アトリビュートは変化しないのですね。

じゃあ、message 変数が変化したら、毎回 text アトリビュートに代入しなくてはいけないのでしょうか? Java で考えたら、JLabel#setText メソッドで毎回設定するのですから、毎回代入するのも普通なのかもしれません......

しかし、JavaFX には便利な機能があるのです!

それがバインディング binding です。

binding はある変数と、他の変数を結び付けておき、一方に変更があったら他方にもその変更が反映されるというものです。

書き方は代入文で右辺の先頭に binding という修飾語を付加するだけです。

    // 変数の場合
    text = binding message;

    // イニシャライザの場合 (クラス名は適当です)
Foo {
    text: binding message
}

この場合、message が変更したら、その変更が text にも反映されるのです。

しかし、binding は一方向なので、text が変更されても message には反映されません。

この binding を使えば、先ほどの問題も一挙解決です。

import javafx.ui.*;

var message:String = "Hello, World!";

Frame {
    title: "Binding Sample"
    width: 200
    height: 100
    visible: true

    content: Label {
        text: binding message
    }
}

message = "こんにちは世界!";

さっそくやってみましょう。

f:id:skrb:20080106030805p:image

ちゃんと反映されました。

binding は使い出のある機能なので、これからもいろいろなところで使っていくと思います。