在异步加载ListView项期间显示一个ProgressIndicator [英] Display a ProgressIndicator during an async loading of ListView items

查看:55
本文介绍了在异步加载ListView项期间显示一个ProgressIndicator的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试执行异步背景ListView项目加载时显示ProgressIndicator.我想要的行为是:

I am trying to display a ProgressIndicator while performing an async background ListView item loading. The behaviour that I desire is:

  1. 在开始加载ListView项目之前,显示带有
  1. Before start loading the ListView items, display a ProgressIndicator with a indeterminate progress;
  2. Asynchronously start loading the ListView items;
  3. After the ListView items loading was finished, hide the ProgressIndicator.

这是我未成功尝试的 ssce :

public class AsyncLoadingExample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        final ListView<String> listView = new ListView<String>();
        final ObservableList<String> listItems = FXCollections.observableArrayList();
        final ProgressIndicator loadingIndicator = new ProgressIndicator();
        final Button button = new Button("Click me to start loading");

        primaryStage.setTitle("Async Loading Example");        

        listView.setPrefSize(200, 250);
        listView.setItems(listItems);

        loadingIndicator.setVisible(false);

        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                // I have hoped it whould start displaying the loading indicator (actually, at the end of this
                // method execution (EventHandler.handle(ActionEvent))
                loadingIndicator.setVisible(true); 

                // asynchronously loads the list view items
                Platform.runLater(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000l); // just emulates some loading time

                            // populates the list view with dummy items
                            while (listItems.size() < 10) listItems.add("Item " + listItems.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally { 
                            loadingIndicator.setVisible(false);  // stop displaying the loading indicator
                        }                   
                    }
                });
            }
        });

        VBox root = VBoxBuilder.create()
            .children(
                StackPaneBuilder.create().children(listView, loadingIndicator).build(), 
                button                  
            )
            .build();

        primaryStage.setScene(new Scene(root, 200, 250));
        primaryStage.show();
    }
}

在此示例中,ListView项是异步加载的.但是,ProgressIndicator不会出现.仍然在此示例中,如果我省略所有Platform.runLater(...)代码,则会显示ProgressIndicator,但是,当然不会加载ListView项.

In this example, the ListView items are loaded asynchronously. However, the ProgressIndicator do not show up. Still in this example, if I omit all the Platform.runLater(...) code, the ProgressIndicator shows up, but, of course, the ListView items are not loaded.

因此,我该如何实现所需的行为?

Thus, how can I achieve the desired behaviour?

推荐答案

问题是,在给出的示例中,我误用了Platform.runLater(...)方法,因此也误用了JavaFX Application Thread.

The problem is that, at the presented example, I am misusing the Platform.runLater(...) method, and consequently, the JavaFX Application Thread.

As mentioned at the Platform.runLater() method documentation, this method

将来在某些未指定的时间在JavaFX Application Thread上运行指定的Runnable.

Run the specified Runnable on the JavaFX Application Thread at some unspecified time in the future.

并且,JavaFX Application Thread是开发人员代码可以从中访问和修改JavaFX场景图的线程,从而直观地反映了所执行的修改.

And, the JavaFX Application Thread is the thread from which the JavaFX scene graph can be accessed and modified by the developer code, visually reflecting the performed modifications.

因此,当我开始从此线程加载ListView项时,UI变得无响应(这也表示为

Thus, when I start loading the ListView items from this thread, the UI becomes unresponsive (this is also stated here) until the loading is finished.

要解决此问题,必须在另一个线程上加载ListView项目,并且必须在应用程序线程上仅执行ListView更新.

To solve the problem, the ListView items must be loaded at another thread and only the ListView update must be performed at Application Thread.

上述更正如下:

public class AsyncLoadingExample extends Application {
    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {
        final ListView<String> listView = new ListView<String>();
        final ObservableList<String> listItems = FXCollections.observableArrayList();
        final ProgressIndicator loadingIndicator = new ProgressIndicator();
        final Button button = new Button("Click me to start loading");

        primaryStage.setTitle("Async Loading Example");        

        listView.setPrefSize(200, 250);
        listView.setItems(listItems);

        loadingIndicator.setVisible(false);

        button.setOnAction(new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                final List<String> loadedItems = new LinkedList<String>();

                // clears the list items and start displaying the loading indicator at the Application Thread
                listItems.clear();
                loadingIndicator.setVisible(true); 

                // loads the items at another thread, asynchronously
                new Thread(new Runnable() {
                    @Override
                    public void run() {
                        try {
                            Thread.sleep(2000l); // just emulates some loading time

                            // populates the list view with dummy items
                            while (loadedItems.size() < 10) loadedItems.add("Item " + loadedItems.size());
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            // just updates the list view items at the
                            // Application Thread
                            Platform.runLater(new Runnable() {
                                @Override
                                public void run() {
                                    listItems.addAll(loadedItems);
                                    loadingIndicator.setVisible(false); // stop displaying the loading indicator
                                }
                            });
                        }
                    }
                }).start();
            }
        });

        VBox root = VBoxBuilder.create()
            .children(
                StackPaneBuilder.create().children(listView, loadingIndicator).build(), 
                button                  
            )
            .build();

        primaryStage.setScene(new Scene(root, 200, 250));
        primaryStage.show();
    }
}

这篇关于在异步加载ListView项期间显示一个ProgressIndicator的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆