import javafx.application.Application; 
import javafx.beans.property.StringProperty; 
import javafx.collections.ObservableList; 
import javafx.scene.Scene; 
import javafx.scene.control.TextArea; 
import javafx.scene.control.TreeItem; 
import javafx.scene.control.TreeView; 
import javafx.scene.layout.BorderPane; 
import javafx.scene.layout.StackPane; 
import javafx.stage.Stage; 

public final class TreeViewPerformanceTest extends Application{ 
private static boolean USE_WORKAROUND = false; 
private static final int DATA_SIZE = 1000*1000; 
private static final int TREE_DATA_SIZE = 1000*100; 

private StringProperty reportProperty; 
private TreeView<String> treeView; 

@Override 
public void start(Stage primaryStage) throws Exception { 
final TextArea report = new TextArea(); 
this.reportProperty = report.textProperty(); 
buildTreeView();	
BorderPane borderPane = new BorderPane(); 
borderPane.setCenter(new StackPane(treeView)); 
borderPane.setBottom(report); 

final Scene scene = new Scene(borderPane, 800, 600); 
primaryStage.setScene(scene); 
primaryStage.sizeToScene(); 
primaryStage.show(); 
} 

private void buildTreeView() { 
Integer[] d1a = new Integer[DATA_SIZE]; 
for(int i=0; i<d1a.length; i++) { 
d1a[i] = i; 
} 
this.treeView = new TreeView<String>(); 
treeView.setFixedCellSize(25); 
final LazyLoadTreeItem treeItem = new LazyLoadTreeItem("Node"); 
treeItem.setExpanded(true); 
treeView.setRoot(treeItem); 
treeView.setEditable(false); 

if(USE_WORKAROUND) { 
treeView.expandedItemCountProperty().addListener((ob,oldValue,newValue)->{ 
int scrollToIndex = treeView.getSelectionModel().getSelectedIndex(); 
treeView.scrollTo(scrollToIndex);	
}); 
} 
} 

private class LazyLoadTreeItem extends TreeItem<String>{ 
LazyLoadTreeItem(String title){ 
super(title); 
} 
@Override 
public ObservableList getChildren() { 
if(this.loaded) { 
return super.getChildren(); 
} 
long t = System.currentTimeMillis(); 
this.loaded = true; 
final String value = getValue(); 

final LazyLoadTreeItem[] d1a = new LazyLoadTreeItem[TREE_DATA_SIZE]; 
for(int i=0; i<d1a.length; i++) { 
d1a[i] = new LazyLoadTreeItem(value + "-" + String.valueOf(i)); 
} 
final ObservableList<TreeItem<String>> children = super.getChildren(); 
TreeItem<String> selectedTreeItem = treeView.getSelectionModel().getSelectedItem(); 

if(USE_WORKAROUND) { 
treeView.getSelectionModel().clearSelection(); 
children.setAll(d1a); 
int scrollToIndex = treeView.getRow(selectedTreeItem); 
treeView.scrollTo(scrollToIndex); 
treeView.getSelectionModel().select(selectedTreeItem); 
}else { 
children.setAll(d1a); 
} 

String result = value + ": time: " + (System.currentTimeMillis() - t); 
reportProperty.set( reportProperty.get() + "\n" + result ); 
return children; 
} 

@Override 
public boolean isLeaf() { 
return false; 
} 


boolean loaded; 
} 

public static void main(String[] args) { 
Application.launch(args);	
} 
} 
