2

I'm trying to add a loading dialog that is shown while some javafx graphic are loading. The problem is that the loading of javafx graphic block the refreshing of loading dialog.

This is my code:

Stage dialogStage;
ProgressBar pb = new ProgressBar();
ProgressIndicator pin = new ProgressIndicator();
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);

final Task<Void> task = new Task<Void>() {
  @Override
  protected Void call() throws Exception {
    System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "START CALL" + ANSI_RESET);

    for (int i = 0; i < 1; i++) {
      System.out.println(ANSI_CYAN + "\tWAIT " + (i + 1) + "s;" + ANSI_RESET);
      try {
        Thread.sleep(500);
      } catch (InterruptedException ex) {
        Logger.getLogger(FXMLDesktopController.class.getName()).log(Level.SEVERE, null, ex);
      }
      System.out.println(ANSI_CYAN + "\tWAITED " + (i + 1) + "s;" + ANSI_RESET);
    }

    Platform.runLater(() -> {
      System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "FIRE APP" + ANSI_RESET);

      startGraphic(anchorDesktop);

      System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "APP FIRED" + ANSI_RESET);
    });

    for (int i = 0; i < 0; i++) {
      System.out.println(ANSI_CYAN + "\tWAIT " + (i + 1) + "s;" + ANSI_RESET);
      try {
        Thread.sleep(1000);
      } catch (InterruptedException ex) {
        Logger.getLogger(FXMLDesktopController.class.getName()).log(Level.SEVERE, null, ex);
      }
      System.out.println(ANSI_CYAN + "\tWAITED " + (i + 1) + "s;" + ANSI_RESET);
    }

    System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "END CALL" + ANSI_RESET);
    return null;
  }

};

pb.progressProperty().bind(task.progressProperty());
pin.progressProperty().bind(task.progressProperty());
dialogStage.show();

task.setOnSucceeded(event -> {
  dialogStage.close();
  System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "CLOSE" + ANSI_RESET);
});

Platform.runLater(() -> {
  System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "START SHOW" + ANSI_RESET);
});

System.out.println(ANSI_CYAN + ANSI_RED_BACKGROUND + "NEW THEAD" + ANSI_RESET);

Thread thread = new Thread(task);
thread.setDaemon(true);
thread.start();

When startGraphic(anchorDesktop) is called is block the animation of the progress bar until all the graphic is loaded. There is a multithreading pipeline for JavaFX graphics?

NickF_93
  • 479
  • 4
  • 16
  • 2
    You're explicitly running `startGraphic` on the FX Application thread. What is that method doing? If it is not changing anything that is actually displayed, it can be run in the background thread. – James_D Dec 20 '17 at 14:57

1 Answers1

0

There is a multithreading pipeline for JavaFX graphics?

No, everything that touches the FX UI (with a few documented exceptions) must be done on the Platform thread.

At the moment you're calling startGraphic() on the platform thread directly, so whatever that method is doing, it'll have to finish execution before anything else can happen on the platform thread (including updating your loading dialog.)

This can be a bit of a pain, but is commonplace in UI toolkits. The normal way around it (assuming startGraphic() does a bunch of UI initialisation) would be to launch the method off the UI thread, and then just wrap the individual UI operations in Platform.runLater() rather than the whole thing in one go. Having lots of small runnables on the platform thread will allow it to schedule updates to the UI in between, including updates to your loading wheel.

Michael Berry
  • 70,193
  • 21
  • 157
  • 216