JavaFX обновляет индикатор выполнения и ожидает завершения потоков - PullRequest
0 голосов
/ 25 апреля 2019

Я пытаюсь обновить индикатор выполнения в Java FX. Моя первая проблема заключалась в том, что окно «не отвечает» вместо фактического обновления. Он просто застыл, а затем, после того как задачи были выполнены, индикатор выполнения заполнился. Поэтому я обнаружил, что мне нужно использовать многопоточность, и реализовал это следующим образом.

overallList.clear();
progressbar.setprogress(0);

for(Object obj : list) {
    class ThreadProgress implements Runnable { // inner class
        public void run() {
            thisList = scrape(obj);
            overallList.add(thisList);
            progressbar.setProgress(progressbar.getProgress() + (double)1/size);
        }
    }

    Thread current = new Thread(new ThreadProgress());
    current.start();
}

textAreaConsole.setText("Total number of things:" + overallList.size());

Но теперь проблема заключается в том, что в последней строке выводится «Общее количество вещей: 0», поскольку потоки фактически не завершают выполнение до того, как машина запускает последнюю строку. Затем я обнаружил несколько способов исправить это, в частности, используя join () или ExecutorService. Я реализовал join () следующим образом.

overallList.clear();
progressbar.setprogress(0);
List<Thread> threads = new ArrayList<Thread>();

for(Object obj : list) {
    class ThreadProgress implements Runnable { // inner class
        public void run() {
            thisList = scrape(obj);
            overallList.add(thisList);
            progressbar.setProgress(progressbar.getProgress() + (double)1/size);
        }
    }

    Thread current = new Thread(new ThreadProgress());
    current.start();
    threads.add(current);
}

for(Thread thread : threads) thread.join(); // with a try-catch loop

textAreaConsole.setText("Total number of things:" + overallList.size());

Но это возвращает меня к первоначальной проблеме, окно снова говорит "не отвечает". То же самое произошло с ExecutorService. Я понятия не имею, что теперь делать.

1 Ответ

3 голосов
/ 25 апреля 2019

См. Пример приложения ниже. Он предоставляет простые ProgressBar и Label, чтобы продемонстрировать, как обновить пользовательский интерфейс с развитием фона Task.

Код также прокомментирован.

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.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class ProgressBarExample extends Application {

    // Create our ProgressBar
    private ProgressBar progressBar = new ProgressBar(0.0);

    // Create a label to show current progress %
    private Label lblProgress = new Label();

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

    @Override
    public void start(Stage primaryStage) {

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

        // Button to start the background task
        Button button = new Button("Start");
        button.setOnAction(event -> startProcess());

        // Add our controls to the scene
        root.getChildren().addAll(
                progressBar,
                new HBox(5) {{
                    setAlignment(Pos.CENTER);
                    getChildren().addAll(
                            new Label("Current Step:"),
                            lblProgress
                    );
                }},
                button
        );

        // Here we will

        // Show the Stage
        primaryStage.setWidth(300);
        primaryStage.setHeight(300);
        primaryStage.setScene(new Scene(root));
        primaryStage.show();
    }

    private void startProcess() {

        // Create a background Task
        Task<Void> task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {

                // Set the total number of steps in our process
                int steps = 1000;

                // Simulate a long running task
                for (int i = 0; i < steps; i++) {

                    Thread.sleep(10); // Pause briefly

                    // Update our progress and message properties
                    updateProgress(i, steps);
                    updateMessage(String.valueOf(i));
                }
                return null;
            }
        };

        // This method allows us to handle any Exceptions thrown by the task
        task.setOnFailed(wse -> {
            wse.getSource().getException().printStackTrace();
        });

        // If the task completed successfully, perform other updates here
        task.setOnSucceeded(wse -> {
            System.out.println("Done!");
        });

        // Before starting our task, we need to bind our UI values to the properties on the task
        progressBar.progressProperty().bind(task.progressProperty());
        lblProgress.textProperty().bind(task.messageProperty());

        // Now, start the task on a background thread
        new Thread(task).start();
    }
}

Редактировать: Добавлены методы setOnFailed() и setOnSucceeded().

...