In my application, I have to build big panes with a lot of content. I will show a ProgressIndicator while the GUI is loading.
My first test, I will show a ProgressIn
You have a Task
that creates a result (i.e. a TabPane
). Therefore it's more convenient to use TabPane
as type parameter instead of Void
also you should call updateProgress to update the progress property and bind that property to the progress property of the ProgressIndicator.
The result can be added to the BorderPane
in the onSucceded handler instead of creating a (more or less) complicated binding:
Task<TabPane> myLongTask;
@Override
public void initialize(URL url, ResourceBundle rb) {
myLongTask = new Task<TabPane>() {
@Override
protected TabPane call() throws Exception {
TabPane tabPane = new TabPane();
List<Tab> tabs = tabPane.getTabs();
final int count = 1000 - 1;
for (int i = 1; i <= count; i++) {
Thread.sleep(10);
Tab newTab = new Tab("Number:" + i);
tabs.add(newTab);
updateProgress(i, count);
}
return tabPane;
}
};
myLongTask.setOnSucceeded(evt -> {
// update ui with results
tabPane = myLongTask.getValue();
borderPane.setCenter(new Pane(tabPane));
});
// add progress indicator to show progress of myLongTask
myProgressIndicator = new ProgressIndicator();
myProgressIndicator.progressProperty().bind(myLongTask.progressProperty());
borderPane.setCenter(new Pane(myProgressIndicator));
new Thread(myLongTask).start();
}
Simply creating the tabs is fast however, and you won't see any progress indicator in the UI. Layouting a TabPane
with 999 Tabs
however is rather slow. The UI will most likely freeze for a short time. You can work around this by adding only a limited number of Tab
s in each frame:
Return a List<Tab>
from the task instead of a TabPane
; these Tab
s should not be added to the TabPane
(yet). You can use a AnimationTimer
to add a fixed number of tabs each frame:
final List<Tab> result = ...; // your tab list
// number of elements added each frame
final int step = 5;
final int size = result.size();
AnimationTimer timer = new AnimationTimer() {
int index = 0;
@Override
public void handle(long now) {
tabPane.getTabs().addAll(result.subList(index, Math.min(size, index+step)));
index += step;
if (index >= size) {
this.stop();
}
}
};
timer.start();
I have change the class like this:
public class SampleController implements Initializable {
@FXML
private BorderPane borderPane;
ProgressIndicator myProgressIndicator;
Task<List<Tab>> myLongTask;
TabPane tabPane = new TabPane();
@Override
public void initialize(URL location, ResourceBundle resources)
{
myLongTask = new Task<List<Tab>>()
{
@Override
protected List<Tab> call() throws Exception
{
List<Tab> newTabs = new ArrayList<Tab>();
final int count = 1000 - 1;
for (int i = 1; i <= count; i++)
{
Tab newTab = new Tab("Number:" + i);
newTabs.add(newTab);
}
return newTabs;
}
};
myProgressIndicator = new ProgressIndicator();
myProgressIndicator.progressProperty().bind(myLongTask.progressProperty());
borderPane.setCenter(new Pane(myProgressIndicator));
new Thread(myLongTask).start();
myLongTask.setOnSucceeded(evt -> {
final List<Tab> result = myLongTask.getValue();
final int step = 5;
final int size = result.size();
AnimationTimer timer = new AnimationTimer() {
int index = 0;
@Override
public void handle(long now) {
tabPane.getTabs().addAll(result.subList(index, Math.min(size, index+step)));
index += step;
if (index >= size) {
this.stop();
}
}
};
timer.start();
borderPane.setCenter(new Pane(tabPane));
});
}
}
Is it this what you mean?