加载时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();
    }
}

但如果任务完成,应用程序将显示窗口.如果我用 Thread.sleep(10) 替换 for 循环内的行,应用程序会显示指示器,毕竟睡眠,它会显示 GUI.

如何在 GUI 尚未加载时显示指示器?

推荐答案

你有一个创建结果的 Task(即一个 TabPane).因此,使用 TabPane 作为类型参数而不是 Void 更方便,您还应该调用 updateProgress 来更新 progress 属性 并将该属性绑定到 ProgressIndicator的progress属性.

可以将结果添加到 onSucceded handler 而不是创建(或多或少)复杂的绑定:

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 来解决此问题:

从任务中返回一个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();

本文地址:https://www.itbaoku.cn/post/978473.html