シーングラフの構築
前回、JavaFX のアプリケーションの構造について説明しました。そこで重要になるのが、シーングラフです。
JavaFX Script であれば宣言的文法でシーングラフを構築できたのですが、JavaFX 2.0 ではそれはできません。なので、Swing/AWT と同じように add or set をずらずらと書いていくことになります。
たとえば、次の図に表したシーングラフを作ってみましょう。
シーングラフを構成する部分だけを次に示します。
VBox root = new VBox(10); root.setAlignment(Pos.CENTER); Scene scene = new Scene(root, 800, 600); stage.setScene(scene); HBox hbox = new HBox(10); hbox.setAlignment(Pos.CENTER); Label label = new Label("Label"); TextBox textBox = new TextBox("TextBox"); textBox.setColumns(20); Button button = new Button("Button"); hbox.getChildren().addAll(label, textBox, button); WebEngine engine = new WebEngine("http://d.hatena.ne.jp/skrb/"); WebView view = new WebView(engine); root.getChildren().addAll(hbox, view);
シーングラフを構成している部分のは主に add と set ですが、コンストラクタで指定している部分もあります。
さて、問題はこのコードを見て、上の図のツリー構造を理解しやすいかどうかです。残念ながら、図とコードがすぐに対応できるわけにはいきません。
Swing/AWT のコードが分かりにくいのも、こういう部分に問題があったと思っています。
この部分を JavaFX 1.x の JavaFX Script では宣言的文法で表すことによって、ツリーとの対応を分かりやすくしていたわけです。
しかし、このコードではあまりにも分かりにくいですね。そこで、少しでも分かりやすくするために JavaFX 2.0 では、各コントロールやシェイプを生成するビルダーが提供されています。
これを使って、上記のコードを書き換えてみたのが、以下のコードです。
stage.setScene( new SceneBuilder().width(800).height(600).root( new VBoxBuilder().spacing(10).alignment(Pos.CENTER).children( new HBoxBuilder().spacing(10).alignment(Pos.CENTER).children( new LabelBuilder().text("Label").build(), new TextBoxBuilder().text("TextBox").columns(20).build(), new ButtonBuilder().text("Button").build() ).build(), new WebViewBuilder().engine(new WebEngine("http://d.hatena.ne.jp/skrb/")).build() ).build() ).build() );
いわゆる流れるインタフェースでシーングラフを構築できます。
ビルダは対応するクラスのプロパティ名と同じメソッドが定義されており、それを使ってプロパティを設定します。戻り値はビルダなので、複数のプロパティを続けて設定することができます。
最後に build メソッドをコールすれば、ビルダが対応するオブジェクトが生成できます。
このコードを見ると、元々のコードに比べれば見やすくなったとはいうものの、やっぱり分かりにくい部分も残ってしまいます。まぁ、Java でやるには限界がありますけど。
これ以上は、Groovy などを使用して宣言的に記述するなどの工夫が必要です。
最後にまとめると、
- JavaFX ではシーングラフで UI の構造を表し、それを add or set メソッドで構築していく
- ビルダを使うことで若干分かりやすいコードが記述できる