加载窗格时的 JavaFx ProgressIndicator (GUI)
JavaFx ProgressIndicator while Loading Pane (GUI)
在我的应用程序中,我必须构建包含大量内容的大窗格。我将在加载 GUI 时显示 ProgressIndicator。
我的第一个测试,我将在将大量选项卡添加到 TabPane 中时显示 ProgressIndicator。
这是我的测试代码:
public class SampleController implements Initializable {
private TabPane tabPane;
@FXML
private BorderPane borderPane;
ProgressIndicator myProgressIndicator;
Task<Void> myLongTask;
@Override
public void initialize(URL location, ResourceBundle resources)
{
myProgressIndicator = new ProgressIndicator();
Pane p1 = new Pane(myProgressIndicator);
tabPane = new TabPane();
Pane p2 = new Pane(tabPane);
myLongTask = new Task<Void>()
{
@Override
protected Void call() throws Exception
{
for (int i = 1; i < 1000; i++)
{
// Thread.sleep(10);
Tab newTab = new Tab("Number:" + i);
tabPane.getTabs().add(newTab);
}
return null;
}
};
borderPane.centerProperty().bind(Bindings.when(myLongTask.runningProperty()).then(p1).otherwise(p2));
new Thread(myLongTask).start();
}
}
但如果任务已完成,应用程序将显示 window。如果我用 Thread.sleep(10)
替换 for 循环内的行,应用程序会显示指示器,毕竟,睡眠,它会显示 GUI。
如何在尚未加载 GUI 时显示指示器?
您有一个 Task
可以创建一个结果(即 TabPane
)。因此,使用 TabPane
作为类型参数而不是 Void
更方便,您也应该调用 updateProgress
to update the progress
property and bind that property to the progress
property of the ProgressIndicator
.
结果可以添加到 onSucceded
handler 中的 BorderPane
而不是创建(或多或少)复杂的绑定:
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();
}
不过,简单地创建选项卡很快,而且您不会在 UI 中看到任何进度指示器。然而,用 999 Tabs
布局 TabPane
相当慢。 UI 很可能会冻结一小段时间。您可以通过在每一帧中仅添加有限数量的 Tab
来解决此问题:
Return 来自任务的 List<Tab>
而不是 TabPane
;这些 Tab
不应添加到 TabPane
中(目前)。您可以使用 AnimationTimer
每帧添加固定数量的选项卡:
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();
我把 class 改成这样:
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));
});
}
}
你是这个意思吗?
在我的应用程序中,我必须构建包含大量内容的大窗格。我将在加载 GUI 时显示 ProgressIndicator。
我的第一个测试,我将在将大量选项卡添加到 TabPane 中时显示 ProgressIndicator。
这是我的测试代码:
public class SampleController implements Initializable {
private TabPane tabPane;
@FXML
private BorderPane borderPane;
ProgressIndicator myProgressIndicator;
Task<Void> myLongTask;
@Override
public void initialize(URL location, ResourceBundle resources)
{
myProgressIndicator = new ProgressIndicator();
Pane p1 = new Pane(myProgressIndicator);
tabPane = new TabPane();
Pane p2 = new Pane(tabPane);
myLongTask = new Task<Void>()
{
@Override
protected Void call() throws Exception
{
for (int i = 1; i < 1000; i++)
{
// Thread.sleep(10);
Tab newTab = new Tab("Number:" + i);
tabPane.getTabs().add(newTab);
}
return null;
}
};
borderPane.centerProperty().bind(Bindings.when(myLongTask.runningProperty()).then(p1).otherwise(p2));
new Thread(myLongTask).start();
}
}
但如果任务已完成,应用程序将显示 window。如果我用 Thread.sleep(10)
替换 for 循环内的行,应用程序会显示指示器,毕竟,睡眠,它会显示 GUI。
如何在尚未加载 GUI 时显示指示器?
您有一个 Task
可以创建一个结果(即 TabPane
)。因此,使用 TabPane
作为类型参数而不是 Void
更方便,您也应该调用 updateProgress
to update the progress
property and bind that property to the progress
property of the ProgressIndicator
.
结果可以添加到 onSucceded
handler 中的 BorderPane
而不是创建(或多或少)复杂的绑定:
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();
}
不过,简单地创建选项卡很快,而且您不会在 UI 中看到任何进度指示器。然而,用 999 Tabs
布局 TabPane
相当慢。 UI 很可能会冻结一小段时间。您可以通过在每一帧中仅添加有限数量的 Tab
来解决此问题:
Return 来自任务的 List<Tab>
而不是 TabPane
;这些 Tab
不应添加到 TabPane
中(目前)。您可以使用 AnimationTimer
每帧添加固定数量的选项卡:
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();
我把 class 改成这样:
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));
});
}
}
你是这个意思吗?