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

TreeViewのモデルとビューの作成を、[前回](http://qiita.com/sipadan2003/items/9305e6c1f52e8e0621d7 "前回")までに進めました。
今回は、MVCパターンに沿うという意味で、TreeViewのコントローラを作ります。

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

```java: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](http://qiita.com/sipadan2003/items/4b909a294b039b0bfd2f "その2")」で作成したTreeCellImplがTreeViewで使われるようになります。

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

最後に、JavaFXのApplicationの派生クラスとFXMLの例を出して、このシリーズは終わりにしたいと思います。
ソースコード一式は、[GitHub](https://github.com/sipadan2003/JFXTreeView201312 "ソースコード一式")に上げておきました。

```java: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);
		}
	}
}
```

```xml: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処理も紹介できたらいいなぁと考えていますが、実現するかどうか…^^;;