Dynamically populating a TreeTableView.
This code example will show the contents of the filesystem tree.
-------------- FileBrowser.java ----------------
import java.io.*;
import java.util.*;
import java.text.*;
import javafx.application.*;
import javafx.stage.*;
import javafx.scene.*;
import javafx.scene.control.*;
import javafx.scene.image.*;
import javafx.scene.layout.*;
import javafx.geometry.*;
import javafx.event.*;
import javafx.collections.*;
import javafx.beans.property.*;
import javafx.util.*;
public class FileBrowser extends Application {
SimpleDateFormat dateFormat = new SimpleDateFormat();
NumberFormat numberFormat = NumberFormat.getIntegerInstance();
Label label;
TreeTableView<File> treeTableView;
@Override
public void start(Stage stage) {
label = new Label();
treeTableView = createFileBrowserTreeTableView();
BorderPane layout = new BorderPane();
layout.setCenter(treeTableView);
layout.setBottom(label);
stage.setScene(new Scene(layout, 600, 400));
stage.show();
}
private TreeTableView<File> createFileBrowserTreeTableView() {
FileTreeItem root = new FileTreeItem(new File("/"));
final TreeTableView<File> treeTableView = new TreeTableView<>();
treeTableView.setShowRoot(true);
treeTableView.setRoot(root);
root.setExpanded(true);
treeTableView.setColumnResizePolicy(TreeTableView.CONSTRAINED_RESIZE_POLICY);
TreeTableColumn<File, FileTreeItem> nameColumn = new TreeTableColumn<>("Name");
nameColumn.setCellValueFactory(cellData ->
new ReadOnlyObjectWrapper<FileTreeItem>((FileTreeItem)cellData.getValue())
);
Image image1 = getImageResource("img/unknown-file-16x16.png");
Image image2 = getImageResource("img/folder-open-16x16.png");
Image image3 = getImageResource("img/folder-close-16x16.png");
nameColumn.setCellFactory(column -> {
TreeTableCell<File, FileTreeItem> cell = new TreeTableCell<File, FileTreeItem>() {
ImageView imageView1 = new ImageView(image1);
ImageView imageView2 = new ImageView(image2);
ImageView imageView3 = new ImageView(image3);
@Override
protected void updateItem(FileTreeItem item, boolean empty) {
super.updateItem(item, empty);
if (item == null || empty || item.getValue() == null ) {
setText(null);
setGraphic(null);
setStyle("");
} else {
File f = item.getValue();
String text = f.getParentFile() == null ? File.separator : f.getName();
setText(text);
String style = item.isHidden() && f.getParentFile() != null ? "-fx-accent" : "-fx-text-base-color";
setStyle("-fx-text-fill: " + style);
if (item.isLeaf()) {
setGraphic(imageView1);
} else {
setGraphic(item.isExpanded() ? imageView2 : imageView3);
}
}
}
};
return cell;
});
nameColumn.setPrefWidth(300);
nameColumn.setSortable(false);
treeTableView.getColumns().add(nameColumn);
TreeTableColumn<File, String> sizeColumn = new TreeTableColumn<>("Size");
sizeColumn.setCellValueFactory(cellData -> {
FileTreeItem item = ((FileTreeItem)cellData.getValue());
String s = item.isLeaf() ? numberFormat.format(item.length()) : "";
return new ReadOnlyObjectWrapper<String>(s);
});
Callback<TreeTableColumn<File, String>,TreeTableCell<File, String>> sizeCellFactory = sizeColumn.getCellFactory();
sizeColumn.setCellFactory(column -> {
TreeTableCell<File, String> cell = sizeCellFactory.call(column);
cell.setAlignment(Pos.CENTER_RIGHT);
cell.setPadding(new Insets(0, 8, 0, 0));
return cell;
});
sizeColumn.setPrefWidth(100);
sizeColumn.setSortable(false);
treeTableView.getColumns().add(sizeColumn);
TreeTableColumn<File, String> lastModifiedColumn = new TreeTableColumn<>("Last Modified");
lastModifiedColumn.setCellValueFactory(cellData -> {
FileTreeItem item = (FileTreeItem)cellData.getValue();
String s = dateFormat.format(new Date(item.lastModified()));
return new ReadOnlyObjectWrapper<String>(s);
});
lastModifiedColumn.setPrefWidth(130);
lastModifiedColumn.setSortable(false);
treeTableView.getColumns().add(lastModifiedColumn);
treeTableView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> {
label.setText(newValue != null ? newValue.getValue().getAbsolutePath() : "");
});
treeTableView.getSelectionModel().selectFirst();
return treeTableView;
}
private Image getImageResource(String name) {
Image img = null;
try { img = new Image(getClass().getResourceAsStream(name)); } catch (Exception e) {}
return img;
}
private class FileTreeItem extends TreeItem<File> {
private boolean expanded = false;
private boolean directory;
private boolean hidden;
private long length;
private long lastModified;
FileTreeItem(File file) {
super(file);
EventHandler<TreeModificationEvent<File>> eventHandler = event -> changeExpand();
addEventHandler(TreeItem.branchExpandedEvent(), eventHandler);
addEventHandler(TreeItem.branchCollapsedEvent(), eventHandler);
directory = getValue().isDirectory();
hidden = getValue().isHidden();
length = getValue().length();
lastModified = getValue().lastModified();
}
private void changeExpand() {
if (expanded != isExpanded()) {
expanded = isExpanded();
if (expanded) {
createChildren();
} else {
getChildren().clear();
}
if (getChildren().size() == 0)
Event.fireEvent(this, new TreeItem.TreeModificationEvent<>(TreeItem.valueChangedEvent(), this, getValue()));
}
}
@Override
public boolean isLeaf() {
return !isDirectory();
}
public boolean isDirectory() { return directory; }
public long lastModified() { return lastModified; }
public long length() { return length; }
public boolean isHidden() { return hidden; }
private void createChildren() {
if (isDirectory() && getValue() != null) {
File[] files = getValue().listFiles();
if (files != null && files.length > 0) {
getChildren().clear();
for (File childFile : files) {
getChildren().add(new FileTreeItem(childFile));
}
getChildren().sort((ti1, ti2) -> {
return ((FileTreeItem)ti1).isDirectory() == ((FileTreeItem)ti2).isDirectory() ?
ti1.getValue().getName().compareToIgnoreCase(ti2.getValue().getName()) :
((FileTreeItem)ti1).isDirectory() ? -1 : 1;
});
}
}
}
} //end class FileTreeItem
} //end class FileBrowser