JavaFX TreeView Tutorial

1- JavaFX TreeView

JavaFX TreeView allows you to create a tree structure with a root item.

2- JavaFX TreeView example

Example below illustrates the creation of a TreeView with a Root Item.
TreeViewDemo.java
package org.o7planning.javafx.treeview;

import org.o7planning.javafx.model.BookCategory;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TreeViewDemo extends Application {

    @Override
    public void start(Stage primaryStage) {

        BookCategory catJava = new BookCategory("JAVA-00", "Java");
        BookCategory catJSP = new BookCategory("JAVA-01", "Jsp");
        BookCategory catSpring = new BookCategory("JAVA-02", "Spring");

        // Root Item
        TreeItem<BookCategory> rootItem = new TreeItem<BookCategory>(catJava);
        rootItem.setExpanded(true);

        // JSP Item
        TreeItem<BookCategory> itemJSP = new TreeItem<BookCategory>(catJSP);

        // Spring Item
        TreeItem<BookCategory> itemSpring = new TreeItem<>(catSpring);

        // Add to Root
        rootItem.getChildren().addAll(itemJSP, itemSpring);

        TreeView<BookCategory> tree = new TreeView<BookCategory>(rootItem);

        StackPane root = new StackPane();
        root.setPadding(new Insets(5));
        root.getChildren().add(tree);

        primaryStage.setTitle("JavaFX TreeView (o7planning.org)");
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
    
}
BookCategory.java
package org.o7planning.javafx.model;

public class BookCategory {

    private String code;
    private String name;

    public BookCategory() {

    }

    public BookCategory(String code, String name) {
        this.code = code;
        this.name = name;
    }

    public String getCode() {
        return code;
    }

    public void setCode(String code) {
        this.code = code;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
   
    @Override
    public String toString()  {
        return this.name;
    }

}
Running the example:

3- TreeView with multiple root items

Note that TreeView is not allowed to contain multiple Root Items but you can hide the root Item and their children will have a display as if they were the root Items of tree.
TreeViewMultiRootDemo.java
package org.o7planning.javafx.treeview;

import org.o7planning.javafx.model.BookCategory;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class TreeViewMultiRootDemo extends Application {

   @Override
   public void start(Stage primaryStage) {

       BookCategory catRoot = new BookCategory("ROOT", "Root");
       // Java
       BookCategory catJava = new BookCategory("JAVA-00", "Java");
       BookCategory catJSP = new BookCategory("JAVA-01", "Jsp");
       BookCategory catSpring = new BookCategory("JAVA-02", "Spring");
       // C#
       BookCategory catCSharp = new BookCategory("C#-00", "CSharp");
       BookCategory catWinForm = new BookCategory("C#-01", "Win Form");

       // Root Item
       TreeItem<BookCategory> rootItem = new TreeItem<BookCategory>(catRoot);
       rootItem.setExpanded(true);

       // Java
       TreeItem<BookCategory> itemJava = new TreeItem<BookCategory>(catJava);
       TreeItem<BookCategory> itemJSP = new TreeItem<BookCategory>(catJSP);
       TreeItem<BookCategory> itemSpring = new TreeItem<BookCategory>(catSpring);
       itemJava.getChildren().addAll(itemJSP, itemSpring);
     
       // CSharp
       TreeItem<BookCategory> itemCSharp = new TreeItem<BookCategory>(catCSharp);
       TreeItem<BookCategory> itemWinForm = new TreeItem<BookCategory>(catWinForm);
       itemCSharp.getChildren().addAll(itemWinForm);
     
       // Add to Root
       rootItem.getChildren().addAll(itemJava,itemCSharp);
     

       TreeView<BookCategory> tree = new TreeView<BookCategory>(rootItem);
     
       // Hide the root Item.
       tree.setShowRoot(false);
     
       StackPane root = new StackPane();
       root.setPadding(new Insets(5));
       root.getChildren().add(tree);

       primaryStage.setTitle("JavaFX TreeView (o7planning.org)");
       primaryStage.setScene(new Scene(root, 300, 250));
       primaryStage.show();
   }

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

4- Tree Cell Editors

JavaFX allows you to edit the data on tree, and in the cells of tree you can use one of Tree Cell Editors as follows:
  • CheckBoxTreeCell
  • ChoiceBoxTreeCell
  • ComboBoxTreeCell
  • TextFieldTreeCell
There classes extend the TreeCell implementation to render a particular control inside the cell when user editing the cell.

TreeView with CheckBox

Example below illustrates the creation of a TreeView with CheckBoxTreeItems. You need to set up Cell Factory for treeView via  setCellFactory method. Cell factory is used to draw the interface at the cell of tree.
With CheckBox:
treeView.setCellFactory(new Callback<TreeView<Layer>, TreeCell<Layer>>() {

   @Override
   public TreeCell<Layer> call(TreeView<Layer> param) {

       return new CheckBoxTreeCell<Layer>();
   }
});

// Or:

treeView.setCellFactory( CheckBoxTreeCell.<Layer> forTreeView());
View full example:
TreeViewCheckBoxDemo.java
package org.o7planning.javafx.treeview;

import org.o7planning.javafx.model.BookCategory;
import org.o7planning.javafx.model.Layer;

import javafx.application.Application;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.CheckBoxTreeItem;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.CheckBoxTreeCell;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TreeViewCheckBoxDemo extends Application {

    @Override
    public void start(Stage primaryStage) {

        Layer layer0 = new Layer("Layers", false);

        Layer layer1 = new Layer("Wet Area", false);
        Layer layer2 = new Layer("Titles", true);
        Layer layer3 = new Layer("Logos", true);

        // Root Item
        TreeItem<Layer> rootItem = new TreeItem<Layer>(layer0);
        rootItem.setExpanded(true);

        // Item 1
        CheckBoxTreeItem<Layer> item1 = new CheckBoxTreeItem<Layer>(layer1);
        item1.setSelected(layer1.isSelected());

        // Item 2
        CheckBoxTreeItem<Layer> item2 = new CheckBoxTreeItem<Layer>(layer2);
        item1.setSelected(layer2.isSelected());

        // Item 3
        CheckBoxTreeItem<Layer> item3 = new CheckBoxTreeItem<Layer>(layer3);
        item1.setSelected(layer3.isSelected());

        // Add to Root
        rootItem.getChildren().addAll(item1, item2, item3);

        TreeView<Layer> treeView = new TreeView<Layer>(rootItem);

        // Set Cell Factory. 

        treeView.setCellFactory(new Callback<TreeView<Layer>, TreeCell<Layer>>() {

            @Override
            public TreeCell<Layer> call(TreeView<Layer> param) {

                return new CheckBoxTreeCell<Layer>();
            }
        });

        StackPane root = new StackPane();
        root.setPadding(new Insets(5));
        root.getChildren().add(treeView);

        primaryStage.setTitle("JavaFX TreeView (o7planning.org)");
        primaryStage.setScene(new Scene(root, 300, 250));
        primaryStage.show();
    }

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

}
Layer.java
package org.o7planning.javafx.model;

public class Layer {

    private String layerName;
    private boolean selected;

    public Layer() {

    }

    public Layer(String layerName, boolean selected) {
        this.layerName = layerName;
        this.selected = selected;
    }

    public String getLayerName() {
        return layerName;
    }

    public void setLayerName(String layerName) {
        this.layerName = layerName;
    }

    public boolean isSelected() {
        return selected;
    }

    public void setSelected(boolean selected) {
        this.selected = selected;
    }

    @Override
    public String toString() {
        return this.layerName;
    }

}

TreeView with ChoiceBox

TreeViewChoiceBoxDemo.java
package org.o7planning.javafx.treeview;

import org.o7planning.javafx.model.XmlTag;

import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.TextArea;
import javafx.scene.control.TreeCell;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.control.cell.ChoiceBoxTreeCell;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.Callback;

public class TreeViewChoiceBoxDemo extends Application {

  @Override
  public void start(Stage primaryStage) {

      XmlTag tag0 = new XmlTag("div");
      XmlTag tag1 = new XmlTag("span");
      XmlTag tag2 = new XmlTag("font");
      XmlTag tag21 = new XmlTag("font");
      XmlTag tag3 = new XmlTag("color");

      // Root Item
      TreeItem<XmlTag> rootItem = new TreeItem<XmlTag>(tag0);
      rootItem.setExpanded(true);

      // Item 1
      TreeItem<XmlTag> item1 = new TreeItem<XmlTag>(tag1);

      // Item 2
      TreeItem<XmlTag> item2 = new TreeItem<XmlTag>(tag2);

      // Item 2.1
      TreeItem<XmlTag> item21 = new TreeItem<XmlTag>(tag21);
      item2.getChildren().add(item21);
      item2.setExpanded(true);

      // Add to Root
      rootItem.getChildren().addAll(item1, item2);

      TextArea textArea = new TextArea();

      TreeView<XmlTag> treeView = new TreeView<XmlTag>(rootItem);
      treeView.setMaxHeight(180);
      treeView.setEditable(true);

      // Set Cell Factory.
      // treeView.setCellFactory( ChoiceBoxTreeCell.<XmlTag> forTreeView());

      treeView.setCellFactory(new Callback<TreeView<XmlTag>, TreeCell<XmlTag>>() {

          @Override
          public TreeCell<XmlTag> call(TreeView<XmlTag> param) {
              // ChoiceBox with 3 option.
              return new ChoiceBoxTreeCell<XmlTag>(tag1, tag2, tag3);
          }
      });

      // Add event handler to item2, it also affects the child items.

      item2.addEventHandler(TreeItem.<XmlTag> valueChangedEvent(),
              new EventHandler<TreeItem.TreeModificationEvent<XmlTag>>() {

                  @Override
                  public void handle(TreeItem.TreeModificationEvent<XmlTag> event) {

                      textArea.appendText("Change to: " + event.getTreeItem().getValue().getTagName() + "\n");
                  }

              });
      // Button
      Button button = new Button("Print Info");
   
      button.setOnAction(new EventHandler<ActionEvent>() {

          @Override
          public void handle(ActionEvent event) {
              textArea.setText(null);
                textArea.appendText("Item0: "+ rootItem.getValue().getTagName());
                textArea.appendText("\nItem1: "+ item1.getValue().getTagName());
              textArea.appendText("\nItem2: "+ item2.getValue().getTagName());
              textArea.appendText("\nItem21: "+ item21.getValue().getTagName());
          }
      });
   
   
      VBox root = new VBox();
      root.setPadding(new Insets(5));
      root.setSpacing(5);
      root.getChildren().addAll(treeView, textArea,button);

      primaryStage.setTitle("JavaFX TreeView (o7planning.org)");
      primaryStage.setScene(new Scene(root, 450, 300));
      primaryStage.show();
  }

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

}
XmlTag.java
package org.o7planning.javafx.model;

public class XmlTag {

    private String tagName;

    public XmlTag() {

    }

    public XmlTag(String tagName) {
        this.tagName = tagName;
    }

    public String getTagName() {
        return tagName;
    }

    public void setTagName(String tagName) {
        this.tagName = tagName;
    }

    @Override
    public String toString() {
        return "<"+this.tagName+">";
    }
   
}