Hi All,
I want to display 1M (may be more) items in TreeView and build tree in background. I am noticed that ScrollBar of TreeView hangs during building of tree. Can you fix it or provide workaround?
Steps for reproduce:
1) Run test application.
2) Click 'Build Tree in Background' button
3) Try to scroll tree use vertical scroll bar.
After loading ~ 300 000 of items impossible to use scroll bar (it just freeze). After loading of 1M items it become scrollable again.
Expected behavior: TreeView should be `scrollable` during building tree in background.
----
package com.company;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
VBox vBox = new VBox();
TreeView<String> treeView = new TreeView<>();
treeView.setShowRoot(false);
treeView.setRoot(new TreeItem<>());
VBox.setVgrow(treeView, Priority.ALWAYS);
vBox.getChildren().addAll(treeView);
HBox hBox = new HBox();
vBox.getChildren().add(hBox);
Label label = new Label();
HBox.setHgrow(label, Priority.ALWAYS);
hBox.getChildren().add(label);
Button button = new Button("Build Tree in Background");
button.setOnAction(event -> {
treeView.getRoot().getChildren().clear();
TreeBuilder treeBuilder = new TreeBuilder(treeView);
label.textProperty().bind(treeBuilder.messageProperty());
treeBuilder.start();
});
hBox.getChildren().add(button);
Scene scene = new Scene(vBox, 1024, 768);
stage.setScene(scene);
stage.show();
}
private class TreeBuilder extends Service {
private TreeView<String> treeView;
public TreeBuilder(TreeView<String> treeView) {
this.treeView = treeView;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Object call() throws Exception {
List<String> chunk = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
chunk.add(UUID.randomUUID().toString());
if (chunk.size() % 10_000 == 0) {
List<TreeItem<String>> treeItems = new ArrayList<>();
for (String s : chunk) {
treeItems.add(new TreeItem<>(s));
}
Platform.runLater(() -> treeView.getRoot().getChildren().addAll(treeItems));
chunk.clear();
updateMessage(String.valueOf(i));
Thread.sleep(100); // The same problem without sleep too
}
}
return null;
}
};
}
}
}
I want to display 1M (may be more) items in TreeView and build tree in background. I am noticed that ScrollBar of TreeView hangs during building of tree. Can you fix it or provide workaround?
Steps for reproduce:
1) Run test application.
2) Click 'Build Tree in Background' button
3) Try to scroll tree use vertical scroll bar.
After loading ~ 300 000 of items impossible to use scroll bar (it just freeze). After loading of 1M items it become scrollable again.
Expected behavior: TreeView should be `scrollable` during building tree in background.
----
package com.company;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Service;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TreeItem;
import javafx.scene.control.TreeView;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;
public class Main extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage stage) throws Exception {
VBox vBox = new VBox();
TreeView<String> treeView = new TreeView<>();
treeView.setShowRoot(false);
treeView.setRoot(new TreeItem<>());
VBox.setVgrow(treeView, Priority.ALWAYS);
vBox.getChildren().addAll(treeView);
HBox hBox = new HBox();
vBox.getChildren().add(hBox);
Label label = new Label();
HBox.setHgrow(label, Priority.ALWAYS);
hBox.getChildren().add(label);
Button button = new Button("Build Tree in Background");
button.setOnAction(event -> {
treeView.getRoot().getChildren().clear();
TreeBuilder treeBuilder = new TreeBuilder(treeView);
label.textProperty().bind(treeBuilder.messageProperty());
treeBuilder.start();
});
hBox.getChildren().add(button);
Scene scene = new Scene(vBox, 1024, 768);
stage.setScene(scene);
stage.show();
}
private class TreeBuilder extends Service {
private TreeView<String> treeView;
public TreeBuilder(TreeView<String> treeView) {
this.treeView = treeView;
}
@Override
protected Task createTask() {
return new Task() {
@Override
protected Object call() throws Exception {
List<String> chunk = new ArrayList<>();
for (int i = 0; i < 1_000_000; i++) {
chunk.add(UUID.randomUUID().toString());
if (chunk.size() % 10_000 == 0) {
List<TreeItem<String>> treeItems = new ArrayList<>();
for (String s : chunk) {
treeItems.add(new TreeItem<>(s));
}
Platform.runLater(() -> treeView.getRoot().getChildren().addAll(treeItems));
chunk.clear();
updateMessage(String.valueOf(i));
Thread.sleep(100); // The same problem without sleep too
}
}
return null;
}
};
}
}
}