重载运行时JavaFX进度指示器停止旋转

时间:2019-03-21 13:33:17

标签: javafx progressdialog busyindicator

我正在尝试使用ProgressIndicator来实现繁忙指示器。但是当重负载开始时,指示器冻结。示例代码如下所示。

import javafx.beans.value.ChangeListener;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.StackPane;
import javafx.scene.paint.Color;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class BusyIcon {

private static Stage busyWindow;

public static void showBusyIcon(final Stage stage) {
    busyWindow = new Stage(StageStyle.UNDECORATED);
    //busyWindow.setOpacity(.3);
    busyWindow.initOwner(stage);
    busyWindow.initModality(Modality.WINDOW_MODAL);

    StackPane stackPane = new StackPane();

    final ProgressIndicator loadingIndicator = new ProgressIndicator();
    loadingIndicator.setVisible(true);
    stackPane.getChildren().add(loadingIndicator);
    Scene scene = new Scene(stackPane, 100, 100);
    scene.setFill(Color.TRANSPARENT);
    busyWindow.setScene(scene);

    ChangeListener<Number> widthListener = (observable, oldValue, newValue) -> {
        double stageWidth = newValue.doubleValue();
        busyWindow.setX(stage.getX() + stage.getWidth() / 2 - stageWidth / 2);
    };
    ChangeListener<Number> heightListener = (observable, oldValue, newValue) -> {
        double stageHeight = newValue.doubleValue();
        busyWindow.setY(stage.getY() + stage.getHeight() / 2 - stageHeight / 2);
    };

    busyWindow.widthProperty().addListener(widthListener);
    busyWindow.heightProperty().addListener(heightListener);

    busyWindow.setOnShown(e -> {
        busyWindow.widthProperty().removeListener(widthListener);
        busyWindow.heightProperty().removeListener(heightListener);
    });
    busyWindow.show();
}

public static void closeBusyIcon(final Stage stage) {
    if (busyWindow != null) {
        busyWindow.close();
        busyWindow = null;
    }
    }
}

import javafx.application.Application;
import javafx.application.Platform;
import javafx.concurrent.Task;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import preloader.BusyIcon;

public class QuestionExample extends Application {

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

@Override
public void start(Stage primaryStage) {
    primaryStage.setTitle("Task Progress Tester");
    StackPane testPane = new StackPane();
    Button b = new Button("Load");
    b.setOnAction((event) -> {
        BusyIcon.showBusyIcon(primaryStage);
        Task t = new Task() {

            @Override
            protected Object call() throws Exception {
                try {
                    addNewComponent(testPane);

                } catch (Exception ex) {
                    ex.printStackTrace();
                }
                return null;
            }
        };
        t.setOnSucceeded((ev) -> {
            BusyIcon.closeBusyIcon(primaryStage);
        });
        new Thread(t).start();

    });

    testPane.getChildren().add(b);
    primaryStage.setScene(new Scene(testPane, 300, 250));
    primaryStage.show();
}

private void addNewComponent(Pane testPane) {
    try {
        /**
         * Some heavy load work will run here
         */
        Thread.sleep(2000);

        Platform.runLater(() -> {
            try {
                /**
                 * We need to change the fx controls here
                 */
                Button b1 = new Button("New Component");
                testPane.getChildren().add(b1);
                /**
                 * This may take some time
                 */
                Thread.sleep(2000);
            } catch (Exception ex) {
                ex.printStackTrace();
            }

        });
    } catch (Exception ex) {
        ex.printStackTrace();
    }

    }

}

BusyIcon用于显示进度指示器。如果我们不使用Platform.runLater,则会抛出“不在FX线程中”的异常。

1 个答案:

答案 0 :(得分:0)

我建议您尝试ControlsFX MaskerPane。关键是在任务运行之前将MaskerPane设置为可见并将其移至AnchorPane的前面。任务完成后,将其设置为不可见并将其移至AnchorPane的背面。

演示:

import javafx.application.Application;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.controlsfx.control.MaskerPane;

/**
 *
 * @author blj0011
 */
public class MaskerPaneTest extends Application
{

    @Override
    public void start(Stage primaryStage)
    {
        MaskerPane mpDeterminate = new MaskerPane();
        MaskerPane mpUndeterminate = new MaskerPane();

        mpDeterminate.setVisible(false);
        mpUndeterminate.setVisible(false);

        Button btn = new Button();
        btn.setText("Determinate");
        btn.setOnAction((ActionEvent event) -> {
            mpDeterminate.setVisible(true);
            mpDeterminate.toFront();
            Task<Void> task = new Task<Void>()
            {
                @Override
                protected Void call() throws Exception
                {
                    for (int i = 0; i < 40000000; i++) {
                        //Do something
                        updateProgress(i, 40000000);
                    }

                    return null;
                }
            };
            mpDeterminate.progressProperty().bind(task.progressProperty());
            task.setOnSucceeded((workerStateEvent) -> {
                mpDeterminate.setVisible(false);
                mpDeterminate.toBack();
            });
            new Thread(task).start();
        });

        Button btn2 = new Button();
        btn2.setText("Undeterminate");
        btn2.setOnAction((ActionEvent event) -> {
            mpUndeterminate.setVisible(true);
            mpUndeterminate.toFront();
            Task<Void> task = new Task<Void>()
            {
                @Override
                protected Void call() throws Exception
                {
                    for (int i = 0; i < 100000; i++) {
                        //Do something
                        System.out.println("working!");
                    }

                    return null;
                }
            };
            mpUndeterminate.progressProperty().bind(task.progressProperty());
            task.setOnSucceeded((workerStateEvent) -> {
                mpUndeterminate.setVisible(false);
                mpUndeterminate.toBack();
            });
            new Thread(task).start();
        });

        StackPane root = new StackPane(mpDeterminate, mpUndeterminate, new VBox(btn, btn2));

        Scene scene = new Scene(root, 300, 250);

        primaryStage.setTitle("Hello World!");
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args)
    {
        launch(args);
    }

}