public TreeItem<Person> getFamilyTree() {
Random random = new Random();
TreeItem<Person> root = new TreeItem();
for (int i = 0; i < 5; i++) {
Person parent = new Person("Parent " + i, "LastName" + i, "Phone" + i);
TreeItem<Person> parentItem = new TreeItem(parent);
for (int j = 0; j < random.nextInt(4); j++) {
Person child = new Person("Child " + i + "-" + j, "LastName" + i, "Phone" + j);
TreeItem<Person> childItem = new TreeItem(child);
parentItem.getChildren().add(childItem);
for (int k = 0; k < random.nextInt(4); k++) {
Person grandChild = new Person("Grandchild " + i + "-" + j + "-" + k, "LastName" + i, "Phone" + k);
TreeItem<Person> grandChildItem = new TreeItem(grandChild);
childItem.getChildren().add(grandChildItem);
}
}
root.getChildren().add(parentItem);
}
return root;
}
Creating a TreeTableView
Sometimes, it is useful to combine a tree and a table. This is especially important when the data that has to be visualized is hierarchical and each entry contains the same type of properties. In this case, the TreeTableView class provides a great solution. As you can see in Figures 6-7 and 6-8, a TreeTableView provides the functionality offered by a TreeView, but for every entry that is shown, we can also show additional columns in a TreeTableView.
The data in a TreeTableView is created using TreeItem instances. In our StarterApp program, we created data in the getFamily() method of the model, as shown in Listing 6-10.
Listing 6-10. Create Hierarchical Data
In this code, we create a number of persons, starting with five “parents.” We then add a random number of children (between zero and three) to each parent, and each of the children can have a random number of children itself—so-called grandchildren. All parents are added to a root node on the TreeItem. Rendering this hierarchical data using a TreeTableView is demonstrated in Listing 6-11.
Listing 6-11. Rendering Hierarchical Data Using a TreeTableView
Node createTreeTableDemoNode() {
TreeTableView<Person> treeTableView = new TreeTableView(model.getFamilyTree());
TreeTableColumn<Person, String> firstNameColumn = new TreeTableColumn("First Name");
firstNameColumn.setCellValueFactory(new TreeItemPropertyValueFactory("firstName"));
firstNameColumn.setPrefWidth(180);
TreeTableColumn lastNameColumn = new TreeTableColumn("Last Name");
lastNameColumn.setCellValueFactory(new TreeItemPropertyValueFactory("lastName"));
lastNameColumn.setPrefWidth(180);
TreeTableColumn phoneColumn = new TreeTableColumn("Phone Number");
phoneColumn.setCellValueFactory(new TreeItemPropertyValueFactory("phone"));
phoneColumn.setPrefWidth(180);
treeTableView.getColumns().addAll(firstNameColumn, lastNameColumn, phoneColumn);
treeTableView.getSelectionModel().selectedItemProperty().addListener((ObservableValue<?
extends TreeItem<Person>>observable, TreeItem<Person> oldValue, TreeItem<Person> newValue) -> {
Person selectedPerson = newValue.getValue();
System.out.println(selectedPerson + " chosen in TreeTableView");
});
treeTableView.setShowRoot(false);
return treeTableView;
}
As you can see from this code, the TreeTableView looks rather similar to the TableView. There are some obvious differences, though. Rather than using TableColumn instances to describe the columns, a TreeTableView requires one to use TreeTableColumn instances. Also, if we want to set the CellValueFactory for a specific column, we can use the convenience class TreeItemPropertyValueFactory, which will make sure the value of the property with the supplied name is rendered in the particular call for a specific column. We now move on to the next tab, ScrollPane/Miscellaneous.