加载 Pane 时的 JavaFx ProgressIndicator (GUI)

标签 java user-interface javafx loading

在我的应用程序中,我必须构建包含大量内容的大 Pane 。当 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 循环内的行,应用程序将显示指示器,并且在 sleep 之后,它会显示 GUI。

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

最佳答案

您有一个Task创建一个结果(即 TabPane )。因此使用TabPane更加方便作为类型参数而不是 Void您也应该调用 updateProgress 更新 progress property并将该属性绑定(bind)到 the progress property of the ProgressIndicator .

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

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

但是,简单地创建选项卡速度很快,而且您不会在用户界面中看到任何进度指示器。布局TabPane 999 Tabs但是速度相当慢。用户界面很可能会短暂卡住。您可以通过仅添加有限数量的 Tab 来解决此问题。每帧中的 s:

返回List<Tab>来自任务而不是 TabPane ;这些Tab s 不应添加到 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();

关于加载 Pane 时的 JavaFx ProgressIndicator (GUI),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35081031/

相关文章:

java - 错误: asking to create a new class while accessing innerclass

python - Tkinter 图像不显示或出错

c - Gtk-关键 ** : IA__gtk_widget_get_parent: assertion `GTK_IS_WIDGET (widget)' failed

c# - 我如何在基于 Android-Java 的应用程序中使用 DataTable。

java - Setter 和 Getter 返回 0 值

JavaFX - 强制 GridPane 的 child 适应单元格的大小

java - 如何确定用户是否在特定 JavaFX 节点外单击?

java - getResourceAsStream();始终为 NULL (Netbeans)

java - Hotspot7 hsdis PrintAssembly 英特尔语法

controls - TreeView 的替代方案