Отображение всплывающего окна с ProgressBar в JavaFX
Как я могу отобразить индикатор выполнения через всплывающее окно и автоматически закрыть, если процесс завершен. Вот мой код.
 Task<ProgressForm> task = new Task<ProgressForm>() {
            @Override 
            public ProgressForm call() throws InterruptedException{
                ProgressForm pf = new ProgressForm();
                for (int i = 1; i <= 10; i++) {
                    pf.activateProgressBar(this);
                    updateProgress(i, 10);
                }
            return pf;                
            }
        };
        task.setOnSucceeded(new EventHandler<WorkerStateEvent>() {
            @Override
            public void handle(WorkerStateEvent t) {
                ProgressForm pf = (ProgressForm)task.getValue();
                pf.getDialogStage().close();
            }
        });
        Thread th = new Thread(task);
        th.run();
класс формы прогресса:
private final Stage dialogStage;
private final ProgressBar pb = new ProgressBar();
private final ProgressIndicator pin = new ProgressIndicator();
public ProgressForm() {
    dialogStage = new Stage();
    dialogStage.initStyle(StageStyle.UTILITY);
    dialogStage.setResizable(false);
    dialogStage.initModality(Modality.APPLICATION_MODAL);
    // PROGRESS BAR
    final Label label = new Label();
    label.setText("alerto");
    pb.setProgress(-1F);
    pin.setProgress(-1F);
    final HBox hb = new HBox();
    hb.setSpacing(5);
    hb.setAlignment(Pos.CENTER);
    hb.getChildren().addAll(pb, pin);
    Scene scene = new Scene(hb);
    dialogStage.setScene(scene);
}
public void activateProgressBar(final Task task) throws InterruptedException {
    pb.progressProperty().bind(task.progressProperty());
    pin.progressProperty().bind(task.progressProperty());
    dialogStage.show();
}
public Stage getDialogStage() {
    return dialogStage;
}
проблема с этим кодом
- если я использую .show (), отображение всплывающего окна плавное, но без индикатора выполнения.
- если я использую .showAndWait (), отображение всплывающего окна требует ручного выхода для закрытия всплывающего окна, но отображается индикатор выполнения.
любой мысли / идеи об этом?
1 ответов
два правила многопоточности в JavaFX:
- код, который изменяет пользовательский интерфейс (создает Stageили изменяет свойства узлов, которые являются частью графа сцены) должны быть выполнены на Потоке приложения JavaFX. Нарушение этого правила будет либо бросатьIllegalStateExceptionS или привести к непредсказуемому поведению.
- код, который занимает много времени для выполнения должны выполняться в фоновом потоке (т. е. не в приложении FX Нить.) Нарушение этого правила приведет к зависанию пользовательского интерфейса.
ваш код нарушает первое правило, потому что он называет ProgressForm конструктор в фоновом потоке. Сначала необходимо настроить пользовательский интерфейс, показать диалоговое окно, а затем запустить фоновый поток.
обратите внимание, что нет необходимости повторно обязать progress свойства индикатора выполнения и индикатора к progress свойство задачи. Как только он связан, он останется связанным до тех пор, пока если только ты его не развязываешь.
довольно сложно исправить ваш код в его нынешнем виде, потому что ваша фоновая задача на самом деле не делает ничего, что занимает какое-либо время. Вот версия того, что вы делаете с паузой:
import javafx.application.Application;
import javafx.concurrent.Task;
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.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
public class ProgressDialogExample extends Application {
    @Override
    public void start(Stage primaryStage) {
        Button startButton = new Button("Start");
        startButton.setOnAction(e -> {
            ProgressForm pForm = new ProgressForm();
            // In real life this task would do something useful and return 
            // some meaningful result:
            Task<Void> task = new Task<Void>() {
                @Override
                public Void call() throws InterruptedException {
                    for (int i = 0; i < 10; i++) {
                        updateProgress(i, 10);
                        Thread.sleep(200);
                    }
                    updateProgress(10, 10);
                    return null ;
                }
            };
            // binds progress of progress bars to progress of task:
            pForm.activateProgressBar(task);
            // in real life this method would get the result of the task
            // and update the UI based on its value:
            task.setOnSucceeded(event -> {
                pForm.getDialogStage().close();
                startButton.setDisable(false);
            });
            startButton.setDisable(true);
            pForm.getDialogStage().show();
            Thread thread = new Thread(task);
            thread.start();
        });
        StackPane root = new StackPane(startButton);
        Scene scene = new Scene(root, 350, 75);
        primaryStage.setScene(scene);
        primaryStage.show();
    }
    public static class ProgressForm {
        private final Stage dialogStage;
        private final ProgressBar pb = new ProgressBar();
        private final ProgressIndicator pin = new ProgressIndicator();
        public ProgressForm() {
            dialogStage = new Stage();
            dialogStage.initStyle(StageStyle.UTILITY);
            dialogStage.setResizable(false);
            dialogStage.initModality(Modality.APPLICATION_MODAL);
            // PROGRESS BAR
            final Label label = new Label();
            label.setText("alerto");
            pb.setProgress(-1F);
            pin.setProgress(-1F);
            final HBox hb = new HBox();
            hb.setSpacing(5);
            hb.setAlignment(Pos.CENTER);
            hb.getChildren().addAll(pb, pin);
            Scene scene = new Scene(hb);
            dialogStage.setScene(scene);
        }
        public void activateProgressBar(final Task<?> task)  {
            pb.progressProperty().bind(task.progressProperty());
            pin.progressProperty().bind(task.progressProperty());
            dialogStage.show();
        }
        public Stage getDialogStage() {
            return dialogStage;
        }
    }
    public static void main(String[] args) {
        launch(args);
    }
}
