Xariez
Xariez

Reputation: 789

Display ProgressBar while dynamically loading GridPane

Heyyo,

So I'm currently working on a JavaFX project, with another Java project handling/serving the data for said project.

While I got most things working, I am still trying to get a ProgressBar to load while loading the data from the data project, which I am having some issues doing.

Currently, I'm looping through the data, creating/adding labels to a GridPane for each "entry". Above it, I declare a JavaFX ProgressBar and add it to my "root wrapper" VBox.

            GridPane wrapper = new GridPane();
            ProgressBar progress = new ProgressBar();    
            viewBox.getChildren().add(progress);           

            int currentRow = 1;     
            for(Map.Entry<String, List<Observation>> item : handler.get(from, to).entrySet()) {                    
                if(item != null) {
                    for(Observation inner : item.getValue()) {
                        if(inner != null) {
                            // Add the data for the datalist
                            wrapper.add(new Label(item.getKey()), 0, currentRow);
                            wrapper.add(new Label(inner.getDate().toString()), 1, currentRow);
                            wrapper.add(new Label(String.valueOf(inner.getValue())), 2, currentRow);

                            currentRow++;
                        }
                    }
                }
            }

            viewBox.getChildren().add(wrapper);

Now, to the things I have tried to achieve this, as I realise this code alone won't do much:

1) Tried wrapping the GridPane in a Task and creating a new thread from said task - Didn't work due to trying to create JavaFX elements while not being in the JavaFX Application Thread

2) Tried wrapping all of the wrapper.add(new Label(...)); in Platform.runLater() - As wrapper is not final and needs to exist both inside and outside of the scope, this did not work either.

3) Tried adding the data entry-by-entry to a temporary map and showing the progress that way by letting the ProgressBar-part run in it's own Task/Thread. Seemed to work as long as I used Thread.join(); afterwards, but seems extremely ineffective.

As always, any and all help is appreciated. If I forgot to mention something required to be able to tell what's going on, please do let me know! I've tried to include everything relevant.

Thanks in advance!

Upvotes: 1

Views: 403

Answers (2)

fabian
fabian

Reputation: 82461

Nodes can be created in any thread, but you must not add them to a scene from a background thread. You shouldn't update properties of nodes in a scene from a background thread either.

GridPane wrapper = new GridPane();
ProgressBar progress = new ProgressBar();
viewBox.getChildren().add(progress);
viewBox.getChildren().add(wrapper);

new Thread(() -> {
    Collection<Map.Entry<String, List<Observation>>> entries = handler.get(from, to).entrySet();
    final double totalEntries = entries.size();
    int currentRow = 1; 
    for(Map.Entry<String, List<Observation>> item : entries) {                    
        if(item != null) {
            for(Observation inner : item.getValue()) {
                if(inner != null) {
                    // Add the data for the datalist
                    final Node[] nds = new Node[] {
                        new Label(item.getKey()),
                        new Label(inner.getDate().toString()),
                        new Label(new Label(String.valueOf(inner.getValue())))
                    };
                    final double newProgress = currentRow / totalEntries;
                    final int r = currentRow;
                    Platform.runLater(() -> {
                        wrapper.addRow(r, nds);
                        progress.setProgress(newProgress);
                    });
                    currentRow++;
                }
            }
        }
    }

}).start();

Upvotes: 0

Andreas
Andreas

Reputation: 94

After you've created your progressbar and it shows up on your GUI use

progress.setProgress(double value)

with an appropriate value depending on how far you've come in your progress.

As an example, you could put the progress like following:

progress.setProgress((currentRow - 1) / handler.get(from, to).entrySet().size())

This line can be put as first line in your for loop. When the whole job is done set the progress to 1 or remove the progress bar.

Upvotes: 1

Related Questions