モデルクラスの考え方
さあ、ではこれを「宣言方式」で書いてみるとどうなるのでしょう? そのままでは、ウィジェット類にどうやってアクセスすればいいのかわかりませんね。
宣言方式では、発想を変える必要があります。JavaFX Scriptには、ある値と別の値を関連付ける「バインド」という機能が用意されているのです。これを利用し、ウィジェットやアトリビュートを別の値(変数など)に関連付け、操作することができるのです。
といっても、ただの変数などにバインドしても役には立ちません。あらかじめ、値を保管するための専用クラスを用意しておき、そこに値の保管用のアトリビュートを用意する。これに、必要なものをバインドして管理する――これが、宣言方式における値の管理方法なのです。
この「値の管理を行うクラス」は、一般に「モデルクラス」と呼ばれます。Javaでも、Swingのコンポーネントで使う値を管理するのにモデルクラスは利用されますね。あれに似たイメージで考えればよいでしょう。
では、バインドとモデルクラスを使って、先ほどのサンプルを宣言方式に書き直してみましょう。
import javafx.ui.*;
class MyDataModel {
attribute labelText: String;
attribute fieldValue: String;
}
var model: MyDataModel = MyDataModel {
labelText: "Hello!"
};
Frame {
centerOnScreen: true
width: 300
height: 120
title: "JavaFX"
content: BorderPanel {
top: Label {
text: bind model.labelText
font: Font {
size: 16
style: [BOLD]
}
}
center: TextField {
value: bind model.fieldValue
}
bottom: Button {
text: "Click"
action: operation(){
var s = model.fieldValue;
var res = "あなたは、{s}と書いた。";
model.labelText = res;
}
}
}
visible: true
}
ずいぶんとすっきりしましたね。ここでは、一番最初に「MyDataModel」という名前のクラスを定義しています。JavaFX Scriptでのクラス定義は、Javaのクラスとは微妙に違いがありますから注意が必要です。JavaFX Scriptのクラスは、以下のような形で定義されます。
class クラス名 [extends スーパークラス] {
attribute アトリビュート: タイプ;
attribute アトリビュート: タイプ;
……略……
operation オペレーション(引数);
operation オペレーション(引数);
……略……
function ファンクション(引数);
function ファンクション(引数);
……略……
}
JavaFX Scriptのクラスは、クラスに用意するアトリビュート、オペレーション、ファンクションの宣言を続けて記述して作成します。注意して欲しいのは、「オペレーションやファンクションは、実装は記述しない」という点です。
とりあえずオペレーションやファンクションについてはひとまず脇に置いておきましょう。、ここではアトリビュートだけのクラスを定義しています。labelTextとfieldValueですね。どちらもStringの値を保管します。
これらがどこで使われているかというと、LabelとTextFieldのtext/valueに、それぞれバインドされているのです。
top: Label {
text: bind model.labelText
……略……
center: TextField {
value: bind model.fieldValue
この部分ですね。「bind」というのが、バインドを行うためのキーワードです。これは、その後に記述した変数やアトリビュートを、このアトリビュートに関連付ける働きをします。
バインドされた2つの値は、実質的に1つの値となります。片方の値を変更すれば、もう片方の値も同じように変わります。例えば、ここではLabelのtext、TextFieldのvalueをそれぞれMyDataModelインスタンスのアトリビュートにバインドしていますね。ということは、このMyDataModelインスタンスのアトリビュートを変更すれば、自動的にLabelやTextFieldのtext/valueも変更されることになるわけです。
このように、使用しているウィジェットやそのアトリビュートを必要に応じてモデルクラスのアトリビュートにバインドすることで、間接的にそれらの値をオペレーション内から操作できるようになります。これが、「JavaFX流」のウィジェット操作法というわけです。