Labelコンポーネント、分割ペイン、増分評価の応用
- HTMLEditorサンプル

次に示すサンプルは、JavaFXの威力をお手軽に見せ付けることのできる、簡単なHTMLエディターだ。

画面は大きく左右に分割され、左に入力したHTMLコードを評価した結果が、右に表示される。

初期状態では以下のように表示される。

HTMLエディタの初期状態

テキストエリア上で、src属性にiGoogleのロゴイメージを持つimgタグを追加したところ、以下のように表示される。

iGoogleのロゴイメージをimgタグで追加したところ

テキストエリアへの編集は、リアルタイムに右ペインに反映される。

このサンプルのポイントは、ラベルや分割ペイン、テキストエリアと言ったUIコンポーネントの使用法、そして増分評価が持つパワーをさらに理解していただくことだ。

以下が、このアプリケーションのソースコードだ。例によって、ポイントとなる部分にはコメント中に番号が振ってある。

リスト4:examples/htmleditor/HTMLEditor.fx

package examples.htmleditor;

import javafx.ui.*;

// モデルクラスの宣言
class HTMLEditorModel {
    attribute content:String;
}
// (1) モデルクラスの属性contentの定義
attribute HTMLEditorModel.content  =
"<b>左のテキストエリアに書いたHTMLが
       ここに表示されます。</b>";

// モデルクラスのインスタンス作成
var model = HTMLEditorModel;

// メインウィンドウの作成
Frame {
    title: "シンプルHTMLエディター", width: 800, height: 400,

    // (2) 分割ペインの利用
    content: SplitPane {
        orientation: HORIZONTAL // 分割方法:横方向

        // 分割ペインの内容はSplitViewクラスの配列となる
        content: [
            SplitView {
                weight: 0.5 // 分割の割合は50%
                content: TextArea {
                    // (3) モデルの属性にバインド
                    text: bind model.content
                }
            },
            SplitView {
                weight: 0.5
                content: Label {
                    // (4) モデルの属性にバインド。
                    //   htmlタグで囲んでおり、LabelクラスによりHTMLとして認識される
                    text: bind "<html>{model.content}</html>"
                }
            }
        ]
    }
    centerOnScreen: true, visible: true
};

ポイントについては以下のとおり。

(1) モデルクラスの属性contentの定義(初期化)を行っている。宣言と定義を分けて記述するのは、前の節で説明したとおりだ。ここで強調したいのは、JavaFX Scriptでの文字列リテラルは、改行文字を含むことが可能という点だ。

(2) 分割ペイン(SplitPane)を用いると、画面を分割してコンポーネントを配置できる。その使用方法は簡単で、SplitPaneの属性orientationに分割方向(縦の場合はVERTICAL、横の場合はHORIZONTAL)を指定し、content属性にjavafx.ui.SplitViewの配列を代入する。各SplitViewで、weight属性を用いて分割の割合を指定することができる(単位はパーセント)。

(3) テキストエリア(javafx.ui.TextArea)のtext属性を、モデルのcontent属性にバインドしている。こうすることにより、テキストエリアの内容が変化したとき、モデルの属性が自動的に更新される。

(4) 分割ペインの右側に表示されるラベルの内容を定義している部分だ。この部分のポイントは2つある。

  • まず、bindキーワードが付与された属性の値にmodel.contentという式が含まれているため、同属性が変更されるたびにラベルのtext属性が再評価されるということだ。そして、モデルのcontent属性はテキストエリアの内容にもバインドされている。つまり、モデルの属性値への変更を、複数のコンポーネントに通知する仕組みが自動化されているということと、バインドされた属性値は双方向(モデル⇔ビュー)に同期をとられるということが言える

  • もう一つは、ラベル(javafx.ui.Label)はHTMLを解釈できるということだ。今回のアプリケーションは、その機能に強く依存している。htmlタグで囲まれた文字列をラベルはHTMLコードだと見なし(ただし、headタグやbodyタグは必要ない)、画面に描画することができる。これは意外と知られていないが、Swingコンポーネントjavax.swing.JLabelが元から持っている機能だ。これにより、スタイリッシュなテキストを表示することは勿論のこと、tableタグを用いて簡単な一覧表を作成することすら可能だ

このサンプルのまとめ

今回のサンプルは、双方向バインドと、HTMLを解釈できるラベルの機能を合わせることで、単純なコードながらも非常にパワフルなアプリケーションを作成できるという例であった。特に、ラベルを使用して簡単にスタイリッシュなテキストを表示できるのはJavaFXの(ひいてはSwingの)大きな強みだ。ぜひ覚えておきたいテクニックである。