1

I am writing a code that reads considerably large arxml file and stores data from it. I have a main class ARXMLParser and a class called ParsedDatabase. I am calling a function from main loadFromArxml and passing the path of file as parameter. The function would read and store that data. I want to update Progress bar in main as the function loadFromArxml is reading data.

I am using class Task and performing my function in it. However I don't know how would I update progress from it.

This is my main code

import java.io.File;

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.TextField;
import javafx.scene.layout.HBox;
import javafx.scene.layout.Priority;
import javafx.scene.layout.VBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import parser.ParsedDatabase;

public class ARXMLParser extends Application {
    private ProgressBar progress;

    @Override
    public void start(Stage primaryStage) {

        TextField arxmlPath = new TextField("");
        arxmlPath.setEditable(false);
        arxmlPath.setFocusTraversable(false);
        arxmlPath.setPromptText("ARXMl File");

        Label arxmlLbl = new Label("No File Selected");

        Button btnArxml = new Button("Browse");
        btnArxml.setOnAction(e -> {
            FileChooser chooser = new FileChooser();
            chooser.setInitialDirectory(new File(System.getProperty("user.dir")));
            FileChooser.ExtensionFilter fileExtensions = new FileChooser.ExtensionFilter("ARXML Files (*.arxml)",
                    "*.arxml");
            chooser.getExtensionFilters().add(fileExtensions);
            File file = chooser.showOpenDialog(primaryStage);
            if (file != null) {
                arxmlPath.setText(file.getAbsolutePath());
                arxmlLbl.setText(file.getName());
            }
        });

        HBox arxmlHbox = new HBox();
        arxmlHbox.setSpacing(10);
        arxmlHbox.getChildren().addAll(arxmlPath, btnArxml);
        HBox.setHgrow(arxmlPath, Priority.ALWAYS);
        HBox.setHgrow(btnArxml, Priority.ALWAYS);

        progress = new ProgressBar();
        progress.setPrefWidth(Double.MAX_VALUE);

        Button btnParse = new Button("Parse");
        btnParse.setOnAction(e -> {
            ParsedDatabase parsedDatabase = new ParsedDatabase();
            if (!arxmlPath.getText().isEmpty()) {
                Task<Void> parse = new Task<Void>() {
                    @Override
                    protected Void call() throws Exception {
                        // Function that reads the file
                        parsedDatabase.loadFromArxml(arxmlPath.getText());
                        return null;
                    }
                };

                progress.progressProperty().bind(parse.progressProperty());
                Thread thread = new Thread(parse);
                thread.setDaemon(true);
                thread.start();
            }
        });

        VBox vBox = new VBox();
        vBox.setFillWidth(true);
        vBox.setSpacing(15);
        vBox.getChildren().addAll(arxmlHbox, arxmlLbl, btnParse, progress);
        vBox.setPadding(new Insets(15, 10, 15, 10));

        Scene scene = new Scene(vBox, 500, 170);
        primaryStage.setTitle("ARXML Parser");
        primaryStage.setResizable(false);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }

    public void setProgressBar(Double value) {
        progress.setProgress(value);
    }

    public double getProgress() {
        return progress.getProgress();
    }
}

And my ParsedDatabase class

package parser;

import java.io.File;
import java.util.Scanner;

public class ParsedDatabase {

    public void loadFromArxml(String arxmlPath) throws Exception {

        File file = new File(arxmlPath);
        Scanner scan = new Scanner(file);
        while (scan.hasNext()) {
            System.out.println(scan.nextLine());
            // Update progress based on file length
        }
        scan.close();
        // Update progress 
        exportToExcel();
        // Update progress
    }

    public void exportToExcel() {
        // Export to excel
       // Update progress
    }
}

I was wondering how to update progress from the method. I do know there is a way I can do it. That is if I call both functions from main and from there updating progress is easy. Something like this

updateProgress(0, 1.0);
parsedDatabase.loadFromArxml(arxmlPath.getText());
updateProgress(0.5, 1.0);
parsedDatabase.exportToExcel();
updateProgress(1, 1.0);

However, The progress bar then will not progress smoothly but will go from 0 to 50 and to 100. I want it to be continuous. If there is a better way to achieve the same thing please let me know. This isn't an assignment. I am just learning concurrency at my own.

Yoshikage Kira
  • 1,070
  • 1
  • 12
  • 20
  • Possible duplicate of [Platform.runLater and Task in JavaFX](https://stackoverflow.com/questions/13784333/platform-runlater-and-task-in-javafx) – deHaar Aug 01 '19 at 14:37
  • In most of the example people are performing the task in main and update it from there. I do not want to perform in the main. I don't know if it is something I should even do. – Yoshikage Kira Aug 01 '19 at 15:22
  • 1
    The code from `loadFromArxml()` should be your `Task`'s `call()` method. Then you update the progress from within the `call()` method. – Zephyr Aug 01 '19 at 15:32
  • Check out this link [Javafx Task - update progress from a method](https://stackoverflow.com/questions/34357005/javafx-task-update-progress-from-a-method) – Iyke Aug 18 '22 at 08:41

1 Answers1

4

One possible solution is to have the code that you are running in loadFromArxml() be moved to the Task's call() method.

Then you can update the progress from within the actual working method. Then just bind your ProgressBar as usual.

Here is a complete example to demonstrate, with loadFromArxml() in a separate class.

ProgressTaskExample.java:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ProgressTaskExample extends Application {

    public static void main(String[] args) {
        launch(args);
    }

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        // The ProgressBar
        ProgressBar progressBar = new ProgressBar(0.0);

        // Button to start the task
        Button button = new Button("Run Task");
        button.setOnAction(event -> {

            System.out.println("Starting task ...");

            // Get the loading Task
            final Task<Void> task = Datasource.loadFromArxml();

            // Catch any exceptions
            task.setOnFailed(wse -> {
                System.out.println("Error");
                task.getException().printStackTrace();
            });

            // Print success when complete
            task.setOnSucceeded(wse -> {
                System.out.println("DONE!");
                progressBar.setStyle("-fx-accent: #19ee15");
            });

            // Bind our ProgressBar's properties
            progressBar.progressProperty().bind(task.progressProperty());

            // Run the task
            new Thread(task).start();

        });

        // Add our nodes to the scene
        root.getChildren().addAll(button, progressBar);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Sample");
        primaryStage.show();
    }
}

Datasource.java:

import javafx.concurrent.Task;

public class Datasource {

    public static Task<Void> loadFromArxml() {
        return new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                // Do your processing here

                updateProgress(0, 100);

                // Run for 5 seconds
                int i = 0;
                while (i < 100) {
                    Thread.sleep(50);
                    i++;

                    updateProgress(i, 100);
                }

                return null;
            }
        };
    }
}
Zephyr
  • 9,885
  • 4
  • 28
  • 63