Yoshikage Kira
Yoshikage Kira

Reputation: 1121

Updating Progress bar from another class

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.

Upvotes: 1

Views: 1248

Answers (1)

Zephyr
Zephyr

Reputation: 10253

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

Upvotes: 4

Related Questions