为什么我的JavaFX Preloader偶尔显示灰色/黑色,有时它会正确加载?

时间:2017-10-12 12:57:53

标签: javafx preloader image-preloader

我正在尝试让我的JavaFX Preloader初始屏幕显示在我的应用程序之前。我正在使用Eclipse IDE,当我点击“运行”时,启动画面将正确显示的时间减少一半,另一半时间我将获得灰色或黑色屏幕,而不是图像所在的位置。

我不确定是什么问题导致它有时只能正确显示。

SplashController

public class SplashController extends Preloader {
  private static final double WIDTH = 676;
  private static final double HEIGHT = 227;
  private Stage preloaderStage;
  private Label progressText;
  private Pane splashScreen;

 public SplashController() {}    

 @Override
  public void init() throws Exception {
    ImageView splash =
        new ImageView(new Image(Demo.class.getResource("pic.png").toString()));
    progressText =
        new Label("VERSION: " + getVersion() + " ~~~ Loading plugins, please wait...");
    splashScreen = new VBox();
    splashScreen.getChildren().addAll(splash, progressText);
    progressText.setAlignment(Pos.CENTER);
  }

  @Override
  public void start(Stage primaryStage) throws Exception {
    this.preloaderStage = primaryStage;
    Scene splashScene = new Scene(splashScreen);
    this.preloaderStage.initStyle(StageStyle.UNDECORATED);
    final Rectangle2D bounds = Screen.getPrimary().getBounds();
    this.preloaderStage.setScene(splashScene);
    this.preloaderStage.setX(bounds.getMinX() + bounds.getWidth() / 2 - WIDTH / 2);
    this.preloaderStage.setY(bounds.getMinY() + bounds.getHeight() / 2 - HEIGHT / 2);
    this.preloaderStage.show();
  }
}

然后在我的主课演示中,我只是:

public class Demo extends Application {
  @Override
  public void start(Stage stage) throws Exception {
     FXMLLoader loader = new 
     FXMLLoader(Demo.class.getResource("FXMLDocument.fxml"));
     GridPane root = loader.load();

                  --------other app  code here---------
  }

  public static void main(String[] args) {
    LauncherImpl.launchApplication(Demo.class, SplashController.class, args);
  }

}

1 个答案:

答案 0 :(得分:0)

可能,您正在JavaFX应用程序线程或应用程序启动中涉及的线程上执行一些长时间运行的进程,这会阻止预加载器的平稳运行。

我建议您查看Oracle Preloader sample并与您的申请进行比较。确保您正确使用Task等并发功能,类似于链接示例。检查链接的示例是否适用于您的环境。

源代码(仅从Oracle Preloader示例链接中复制)

请注意,在主LongAppInit应用程序类的start方法中,如何生成Task和线程,以确保在JavaFX应用程序线程上不会发生长应用程序启动。另请参阅在长应用程序初始化期间如何在不同时间调用notifyPreloader()应用程序方法,以使预加载器知道初始化过程的当前状态,以便它可以在UI中实时准确地反映进度。

LongAppInitPreloader.java

public class LongAppInitPreloader extends Preloader {
    ProgressBar bar;
    Stage stage;
    boolean noLoadingProgress = true;

    private Scene createPreloaderScene() {
        bar = new ProgressBar(0);
        BorderPane p = new BorderPane();
        p.setCenter(bar);
        return new Scene(p, 300, 150);
    }

    public void start(Stage stage) throws Exception {
        this.stage = stage;
        stage.setScene(createPreloaderScene());
        stage.show();
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        //application loading progress is rescaled to be first 50%
        //Even if there is nothing to load 0% and 100% events can be
        // delivered
        if (pn.getProgress() != 1.0 || !noLoadingProgress) {
          bar.setProgress(pn.getProgress()/2);
          if (pn.getProgress() > 0) {
              noLoadingProgress = false;
          }
        }
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification evt) {
        //ignore, hide after application signals it is ready
    }

    @Override
    public void handleApplicationNotification(PreloaderNotification pn) {
        if (pn instanceof ProgressNotification) {
           //expect application to send us progress notifications 
           //with progress ranging from 0 to 1.0
           double v = ((ProgressNotification) pn).getProgress();
           if (!noLoadingProgress) {
               //if we were receiving loading progress notifications 
               //then progress is already at 50%. 
               //Rescale application progress to start from 50%               
               v = 0.5 + v/2;
           }
           bar.setProgress(v);            
        } else if (pn instanceof StateChangeNotification) {
            //hide after get any state update from application
            stage.hide();
        }
    }  
 }

LongAppInit.java

public class LongInitApp extends Application {
    Stage stage;
    BooleanProperty ready = new SimpleBooleanProperty(false);

    private void longStart() {
        //simulate long init in background
        Task task = new Task<Void>() {
            @Override
            protected Void call() throws Exception {
                int max = 10;
                for (int i = 1; i <= max; i++) {
                    Thread.sleep(200);
                    // Send progress to preloader
                    notifyPreloader(new ProgressNotification(((double) i)/max));
                }
                // After init is ready, the app is ready to be shown
                // Do this before hiding the preloader stage to prevent the 
                // app from exiting prematurely
                ready.setValue(Boolean.TRUE);

                notifyPreloader(new StateChangeNotification(
                    StateChangeNotification.Type.BEFORE_START));

                return null;
            }
        };
        new Thread(task).start();
    }

    @Override
    public void start(final Stage stage) throws Exception {
        // Initiate simulated long startup sequence
        longStart();

        stage.setScene(new Scene(new Label("Application started"), 
            400, 400));

        // After the app is ready, show the stage
        ready.addListener(new ChangeListener<Boolean>(){
            public void changed(
                ObservableValue<? extends Boolean> ov, Boolean t, Boolean t1) {
                    if (Boolean.TRUE.equals(t1)) {
                        Platform.runLater(new Runnable() {
                            public void run() {
                                stage.show();
                            }
                        });
                    }
                }
        });;                
    }
}