ツリーコンポーネント、遅延バインド
- ファイルシステムのツリー表示サンプル

では、今回の特集で取り上げる最後のサンプルとして、ファイルシステムのツリー表示を行うサンプルを紹介する。このサンプルはコードが単純になるよう、ファイルシステム全体ではなく、「カレントディレクトリ以下の構造を、ツリーコンポーネントを用いて表示する」というだけのサンプルだ。

アプリケーションを起動すると、以下の画像のように、カレントディレクトリ以下のファイルシステムの構造がツリー表示される。

ファイルシステムのツリー表示サンプル

最も注目すべきポイントは、ツリーコンポーネントを構築するために、関数の再帰呼び出しを使用している部分だ。そこで使用しているbind lazyキーワードによる遅延増分評価が持つ効果もしっかり押さえておきたい。

このサンプルのソースコードを以下に示す。

リスト6:examples/filesystem/FileSystemTree.fx

package examples.filesystem;

import javafx.ui.*;
import java.io.File;

// メインウィンドウの作成
Frame {
    title: "簡易エクスプローラ", width: 400, height: 400,
    // (1) ツリーコンポーネントの使用
    content: Tree {
        showRootHandles: true // ルート要素に、折り畳み用のハンドルを表示するか
        // (2) オペレーションに対するバインド
        root: bind getFileSystemTree(new File("."))
    }
    centerOnScreen: true, visible: true
};

operation getFileSystemTree(file:File):TreeCell {
    // (3) ディレクトリの場合とファイルの場合で条件分岐
    if (file.directory) {
        // (4) ディレクトリの場合はcells属性に注目
        return TreeCell {
            text: file.name  // セルに表示するテキスト

            // bind lazyを用いた遅延バインド
            cells: bind lazy
                foreach (child in file.listFiles())
                    getFileSystemTree(child) // 再帰呼び出し
        };
    } else {
        // ファイルの場合は、単一のツリーセルを返す。
        return TreeCell {
            text: file.name
        };
    }
}

ポイントは以下の通りだ。

(1) ツリーコンポーネント(javafx.ui.Tree)を、メインウィンドウのコンテンツに配置している。javafx.ui.Treeの使用方法は、root属性にjavafx.ui.TreeCellクラスのインスタンスを格納するだけだ。 javafx.ui.TreeCellは以下のような構造を持つクラスだ。

TreeCell {
    text: String     // 項目の横に表示するテキスト
    cells: TreeCell* // このセルが子要素を持つ場合、TreeCellの配列を持つ
}

つまり、ツリー構造に従ってTreeCell自身が入れ子構造を取るのだ(cells属性)。

(2) ツリーのroot属性は、オペレーションgetFileSystemTreeが返す戻り値を増分評価の対象としている。ここでは、ツリーのルート要素となるカレントディレクトリのインスタンスをオペレーションの引数として呼び出している。

(3) オペレーションgetFileSystemTreeは、ツリーの要素一つ分を表すTreeCellクラスのインスタンスを作成して返す。java.io.Fileといった通常のJavaクラスを問題なく扱えていること、Javaのプロパティ(setter/getter)は、JavaFXにおいて「.」演算子でアクセスできることを軽く押さえておこう。

(4) ツリーのセルが表す要素がディレクトリだった場合が、このサンプルの一番のキモとなる部分だ。 ディレクトリの場合は、そのディレクトリが持つファイル/サブディレクトリをツリーの子要素として表示する必要がある。それはつまりTreeCellクラスのcells属性が適切な値を返せばよいということだが、このサンプルではどうなっているだろうか。 今回はcells属性はbind lazyキーワードにより、「遅延評価」が行われるように指定されている。この指定により、実際にcells属性がアクセスされるとき(つまり、ツリーのアイコンがクリックされて子要素がオープンされる瞬間)までcells属性の値を評価するのを遅らせている。 評価される式自体は、getFileSystemTreeオペレーションの再帰呼び出しを子要素すべてに対して行うことで、コンパクトなコードを実現している。

このサンプルのまとめ

さて、このサンプルではツリーコンポーネントの使用方法、bind lazyの利用方法について学んだがいかがであろうか。ここまでできれば、すでに学んだ分割ペインやテーブルコンポーネントと併せて、以下のような簡易エクスプローラを作成するのもそれほど難しくはないので、読者諸兄もぜひトライしてみていただきたい。

簡易エクスプローラ

特集のまとめ

さて、今回の特集は以上で終わりとしたいが、いかがだっただろうか。

他にも利用できるUIコンポーネントは非常に多く、その全てを解説するのは限られた字数の中では不可能だ。しかし、配布されているディストリビューションの中には、それらほとんどについてソースコードが添付されている。そうしたクラスのソースコードを読み、理解できるレベルの説明は行ったつもりだ。

また、JavaFX Scriptのオリジナルであるプログラミング言語「F3」を開発した、Sun Microsystemsの社員Chris Oliver氏のブログにUIコンポーネントのリファレンスが載っている(ただし英語)ので、活用していただきたい。

JavaFXを用いて行うプログラミングが今までのSwingアプリケーション開発に比べてはるかに生産性が高いこと、こうしたプログラミング方法を用いて各種デバイスのUIを作成できるという可能性の素晴らしさを感じ取っていただけたら幸いである。