LoginSignup
5
6

More than 5 years have passed since last update.

JavaFX TreeViewのカスタマイズ - その4:TreeViewコントローラの作成

Last updated at Posted at 2013-12-01

TreeViewのモデルとビューの作成を、前回までに進めました。
今回は、MVCパターンに沿うという意味で、TreeViewのコントローラを作ります。

SwingもそうですがJavaFXにもコントローラのAPIがあるわけではなく、開発者がゼロから作り上げるものです。
といっても、今回はとりあえず「TreeCellでラベル名の編集ができる」ことが目的なので、コントローラはあまり作り込んでいません。

TreeViewController.java
package jfxtreeview;

import javafx.scene.control.SelectionMode;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.util.Callback;

/**
 *JavaFXの{@link javafx.scene.control.TreeView}を制御するコントローラです。
 */
public class TreeViewController {
    /**
     *コンストラクタです。
     *@param treeview {@link javafx.scene.control.TreeView}オブジェクト
     */
    public TreeViewController(TreeView<TreeItemData> treeview) {
        //TreeViewのモデル(TreeItem)を構築する
        final TreeItem<TreeItemData> rootNode = new TreeItem<>(new TreeItemData("Root", TreeItemData.Type.GROUP));
        final TreeItem<TreeItemData> node0 = new TreeItem<>(new TreeItemData("Node0", TreeItemData.Type.GROUP));
        final TreeItem<TreeItemData> node1 = new TreeItem<>(new TreeItemData("Node1", TreeItemData.Type.GROUP));
        rootNode.setExpanded(true);
        rootNode.getChildren().add(node0);
        rootNode.getChildren().add(node1);
        for(int i=0; i<3; i++){
            node0.getChildren().add(new TreeItem<>(new TreeItemData("Node0"+i)));
            node1.getChildren().add(new TreeItem<>(new TreeItemData("Node1"+i)));
        }
        //TreeItemのルートをTreeViewに設定する
        treeview.setRoot(rootNode);
        //独自TreeCellを生成するクラスを設定する
        treeview.setCellFactory(new TreeViewCellFactory());
    }

    /**
     *TreeItemのデータ名が変更されたときに呼び出されます。
     *@param treeItem データ名が変更されたTreeItem
     *@param name 新しいデータ名
     *@return 新しいデータ名を反映したTreeItem (データ名の変更をキャンセルする場合はnullを返す)
     */
    protected TreeItemData treeItemDataRenamed(TreeItem<TreeItemData> treeItem, String name){
        return new TreeItemData(name, treeItem.getValue().getType());
    }

    /**
     *独自のTreeCellを生成するファクトリクラスです。
     */
    final class TreeViewCellFactory implements Callback<TreeView<TreeItemData>,TreeCell<TreeItemData>> {
        @Override
        public TreeCell<TreeItemData> call(TreeView<TreeItemData> treeview){
            return new TreeCellImpl(TreeViewController.this);
        }
    }
}

ポイントは2つです。

1つめは、TreeView.setCellFactory()を使っている点です。これにより、「その2」で作成したTreeCellImplがTreeViewで使われるようになります。

2つめは、treeItemDataRenamed()です。これは「その3」のTreeCellGraphからコールバックされるものです。今回の例ではコールバックされるものはこの1つだけですが、たとえばTreeItemを追加したり削除したり、また移動したりする機能をTreeViewに追加する場合には、新たにコールバックされるメソッドを追加していきます。つまり、TreeViewの制御をコントローラが担うということです。

最後に、JavaFXのApplicationの派生クラスとFXMLの例を出して、このシリーズは終わりにしたいと思います。
ソースコード一式は、GitHubに上げておきました。

Main.java
package jfxtreeview;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.TreeView;
import javafx.scene.image.Image;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;

public final class Main extends Application {
    private TreeViewController controller;

    public static void main(String[] args) {
        Application.launch(args);
    }

    @Override
    public void start(final Stage stage) {
        try {
            //ウィンドウのアイコンを設定
            final Image img16 = new Image(getClass().getResourceAsStream("treeviewsample16.jpg"));
            final Image img32 = new Image(getClass().getResourceAsStream("treeviewsample32.jpg"));
            //GUI構築
            final Pane root = (Pane)FXMLLoader.load(this.getClass().getResource("fxml001.fxml"));
            this.controller =new TreeViewController((TreeView<TreeItemData>)root.lookup("#treeview"));
            stage.setScene(new Scene(root));
            stage.setTitle("TreeView Sample");
            stage.getIcons().addAll(img16, img32);
            stage.show();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
fxml001.fxml
<?xml version="1.0" encoding="UTF-8"?>

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.geometry.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.paint.*?>

<BorderPane prefHeight="400.0" prefWidth="600.0" xmlns:fx="http://javafx.com/fxml">
  <left>
    <TreeView fx:id="treeview" editable="true" prefHeight="200.0" prefWidth="200.0" showRoot="false" />
  </left>
  <center>
    <TextArea fx:id="textarea" />
  </center>
  <padding>
    <Insets bottom="5.0" left="5.0" right="5.0" top="5.0" />
  </padding>
</BorderPane>

いつかはTreeViewでのDrag and Drop処理も紹介できたらいいなぁと考えていますが、実現するかどうか…^^;;

5
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
5
6