在我的应用程序中,我必须构建包含大量内容的大窗格。我将在GUI加载时显示ProgressIndicator。
我的第一次测试,我将在TabPane中添加大量标签时显示ProgressIndicator。
那是我的测试代码:
{Binding Path=DataContext.Command1, ElementName=MyItemsControl}
但是,如果任务完成,应用程序将显示窗口。如果我用for 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();
}
}
替换for循环中的行,应用程序会显示指示符,然后睡眠,它会显示GUI。
如果尚未加载GUI,如何显示指示符?
答案 0 :(得分:2)
您有Task
创建结果(即TabPane
)。因此,使用TabPane
作为类型参数而非Void
更方便您也应该调用updateProgress
来更新progress
property并将该属性绑定到{{3} }}
可以将结果添加到the progress
property of the ProgressIndicator
中的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 TabPane
来布置Tabs
相当慢。用户界面很可能会在很短的时间内冻结。您可以通过在每个帧中仅添加有限数量的Tab
来解决此问题:
从任务中返回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();
答案 1 :(得分:0)
我改变了这样的课程:
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));
});
}
}
这是你的意思吗?