2013年1月25日金曜日

JavaFX TreeViewとTreeItem

JavaFXのTreeViewを使ってみた.ファイルツリー的なものを作ろうと思ったら,TreeItemのドキュメントにすでに書いてあった.
で,それを自分なりに整理して書いてみた.

まずは,ファイルツリーの要素を表すクラスを,TreeItem<File>を継承して作る.

import java.io.File;
import javafx.collections.ObservableList;
import javafx.collections.FXCollections;
import javafx.scene.control.TreeItem;

// ファイルツリーの根や分岐や葉を表すクラス
// 根は値を持たないものとする
public class FileTreeItem extends TreeItem<File> {
    public FileTreeItem(){
        this(null);
    }

    public FileTreeItem(final File file){
        // 要素の値を設定
        super(file);
    }

    // 木の要素が葉かどうか(末端かどうか)を返す
    // 要素が持つ値は根の場合はnullで,
    // それ以外では通常のFileオブジェクトになる
    @Override
    public boolean isLeaf(){
        File file = getValue();
        return file != null && file.isFile();
    }

    @Override
    public ObservableList<TreeItem<File>> getChildren(){
        // 既に一度子要素を作っている場合はそのキャッシュを利用する
        ObservableList<TreeItem<File>> children = super.getChildren();
        if(!children.isEmpty())
            return children;
 
        // 根にファイルを追加する前に通る
        File file = getValue();
        if(file == null)
            return children;

        // ファイルの場合
        if(!file.isDirectory()){
            return FXCollections.emptyObservableList();
        }

        // ディレクトリの場合
        File [] files = file.listFiles();
        for(File f : files){
            children.add(new FileTreeItem(f));
        }
        return children;
    }
}

根の持つ値をnullにしたのは,TreeViewが当たり前ではあるが根として1つしか要素を持てないため.
MacやLinuxでは/だけがルートなので良いが,Windowsの場合CドライブやDドライブと言った
複数のルートが存在するので,何も値を持たない根を用意し,その下にルートを置くようにしたいから.

表示部分は次のように.

import java.io.File;
import javafx.application.Application;
import javafx.scene.control.TreeView;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Simple extends Application {
    public static void main(String [] args){
        launch(args);
    }

    public void start(Stage primaryStage){
        // ルートファイルのリストを取得
        File [] rootFiles = File.listRoots();
        FileTreeItem root = new FileTreeItem();
        // 根の要素に各ルートファイルを追加していく
        for(File f : rootFiles){
            root.getChildren().add(new FileTreeItem(f));
        }

        // 根の要素を渡してファイルツリーのビューを作成
        TreeView treeView = new TreeView(root);
        // 無駄なnullのルートは表示しないようにする
        treeView.setShowRoot(false);
        // TreeViewをシーンに追加して表示する
        Scene scene = new Scene(treeView);
        primaryStage.setWidth(640);
        primaryStage.setHeight(480);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
}

Macでは動作確認したけど,これでWindowsでも上手く各種ドライブが
表示されるかどうかは未確認.

Javaはジェネリクスが出た頃くらいから触っていなかったのでドキュメントを読むのも
一苦労だ・・・.コンパイラに型が間違ってるとか言われまくった.

0 件のコメント:

コメントを投稿