2017-10-01 2 views
2

J'essaie actuellement de créer un écran de démarrage pour mon programme, car il faut un certain temps pour démarrer. Le problème est qu'il faut du temps pour créer l'interface graphique (création de dialogues, mise à jour de tables, etc.). Et je ne peux pas déplacer la création de l'interface graphique vers un thread d'arrière-plan (comme la classe "Task"), car j'obtiendrai une exception "Not on FXApplication Thread". J'ai essayé d'utiliser:Chargement de l'interface graphique JavaFX en arrière-plan

Platform.runLater(new Runnable() { 
      public void run() { 
      //create GUI 
    } 
} 

Et la méthode « appel » d'une tâche:

public class InitWorker extends Task<Void> { 

    private Model model; 
    private ViewJFX view; 

    public InitWorker(Model model) { 
     this.model = model; 
    } 

    @Override 
    protected Void call() throws Exception { 
      View view = new View(); 
      Collection collection = new Collection(); 
      //do stuff 
    } 
} 

Quand j'ai écrit le programme Swing je pouvais afficher et mettre à jour l'écran de démarrage sur le EventDispatchThread, sans tout réel concordance. Le code ressemblait à ceci:

public void build() { 
     MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Menus"); 
     menuCreator = new MenuCreatorOld (model, this); 
     menuCreator.createMenu(); 
     MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE, "Creating Toolbar"); 
     toolBar = menuCreator.createToolBar(); 

     createWesternPanelToolBar(); 

     shoppingPanel = new ShoppingListOld(model, this, collectionController, shoppingController, controller); 

     centerTabbedPane = new JTabbedPane(); 
      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Collection"); 
      collectionPanel = new CollectionOld(model, collectionController, this, controller); 
      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Wish List"); 
      wishPanel = new WishListOld(model, this, collectionController, wishController, controller); 

      MainOld.updateProgressBar(MainOld.PROGRESSBAR_VALUE++, "Creating Folders Table"); 
      //and so on 
} 

public static void updateProgressBar(int progressValue, String text) { 
    System.out.println("Loading Bar Value:"+progressValue); 
    progressBar.setValue(progressValue); 
    loadingLabel.setText(text); 
    progressBar.setString(text); 
} 

Est-il possible de créer l'interface graphique en arrière-plan tout en affichant un écran d'accueil avec une barre de chargement?

Edit:

J'ai regardé mon code et a été en mesure de réduire le temps de démarrage de 5 secondes. La plupart des boîtes de dialogue extraient des données de la base de données lors de leur création. J'ai donc déplacé la création des dialogues dans leurs méthodes getter. Cela a entraîné une amélioration de 3 secondes. Mais j'aimerais quand même savoir s'il y a moyen de créer l'interface graphique sur un thread d'arrière-plan.

Edit:

Comme suggéré, j'ai essayé également d'utiliser "RunLater" dans une "tâche". De cette façon, je peux créer l'interface graphique et afficher le SplashScreen, mais je ne peux pas mettre à jour la barre de progression et l'étiquette de progression, car la création de l'interface graphique bloque le thread d'application JavaFX. La barre de progression et l'étiquette sont mises à jour uniquement après la création complète de l'interface graphique.

Voici un exemple que vous les gars peuvent courir (je l'ai enlevé l'écran de démarrage et seulement gardé la barre de progression et l'étiquette de progrès):

public class InitWorker extends Task<Void> { 


    private static ProgressBar progressBar; 
    private static Label progressLabel; 
    private static double PROGRESS_MAX = 5; 
    private double loadingValue; 

    public InitWorker() { 
     loadingValue = 0; 
    } 

    @Override 
    protected void succeeded() { 
     System.out.println("Succeeded"); 
    } 

    @Override 
    protected void failed() { 
     System.out.println("Failed"); 
    } 

    @Override 
    protected Void call() throws Exception { 
     System.out.println("RUNNING"); 
     Platform.runLater(new Runnable() { 
      public void run() { 
       displaySplashScreen(); 
       for(int i=0; i<10; i++) { 
        try { 
         Thread.sleep(200); 
        } catch (InterruptedException e) { 
         // TODO Auto-generated catch block 
         e.printStackTrace(); 
        } 
        updateProgressBar(loadingValue++, "Label "+i); 
        Stage stage = new Stage(); 
        Label label = new Label("Label " + i); 
        VBox panel = new VBox(); 
        panel.getChildren().add(label); 
        Scene scene = new Scene(panel); 
        stage.setScene(scene); 
        stage.centerOnScreen(); 
        stage.show(); 
       } 
//    updateProgressBar(1, "Initializing..."); 

      }}); 

     return null; 
    } 


    public void updateProgressBar(double loadingValue, String text) { 
     progressBar.setProgress(loadingValue/PROGRESS_MAX); 
     progressLabel.setText(text); 
    } 




    public static void displaySplashScreen() { 

     Stage progressBarStage = new Stage(); 
     progressBar = new ProgressBar(); 
     Scene progressBarScene = new Scene(progressBar); 
     progressBarStage.setScene(progressBarScene); 

     Stage progressLabelStage = new Stage(); 
     progressLabel = new Label("Loading..."); 
     progressLabel.setPadding(new Insets(5)); 
     progressLabel.setStyle("-fx-background-color: red"); 
     Scene progressLabelScene = new Scene(progressLabel); 
     progressLabelStage.setScene(progressLabelScene); 

     double progressBarWidth = 500; 
     double progressBarHeight = 75; 

     //muss angezeigt werden, um sie abhängig von Größe zu positionieren 
     progressBarStage.show(); 
     progressLabelStage.show(); 
     // 

     progressBarStage.setWidth(progressBarWidth); 
     progressBarStage.setHeight(progressBarHeight); 
     progressBarStage.centerOnScreen(); 
     progressBarStage.centerOnScreen(); 
     progressLabelStage.setY(progressLabelStage.getY() + 25); 


    } 

} 
+3

La création de l'interface graphique ne devrait pas prendre beaucoup de temps. Cela peut prendre du temps pour récupérer les données, etc., que vous allez afficher dans l'interface graphique, mais vous pouvez le faire sur le fil d'arrière-plan. Êtes-vous sûr que la création de l'interface graphique réelle prend du temps? –

+0

J'ai regardé mon code et j'ai été capable de réduire le temps de démarrage de 5 secondes. La plupart des boîtes de dialogue extraient des données de la base de données lors de leur création. J'ai donc déplacé la création des dialogues dans leurs méthodes getter. Cela a entraîné une amélioration de 3 secondes. Mais j'aimerais quand même savoir s'il existe en général un moyen de créer l'interface graphique dans un thread d'arrière-plan. – maumau

+0

Quel matériel et système d'exploitation utilisez-vous? Pouvez-vous fournir un [mcve] exposant le problème? – Itai

Répondre

0

Voir Task documentation titled "A Task Which Modifies The Scene Graph", ce qui donne un exemple:

final Group group = new Group(); 
Task<Void> task = new Task<Void>() { 
    @Override protected Void call() throws Exception { 
     for (int i=0; i<100; i++) { 
      if (isCancelled()) break; 
      final Rectangle r = new Rectangle(10, 10); 
      r.setX(10 * i); 
      Platform.runLater(new Runnable() { 
       @Override public void run() { 
        group.getChildren().add(r); 
       } 
      }); 
     } 
     return null; 
    } 
}; 

L'exemple ci-dessus ajoute les rectangles au graphe de scène via un appel de 100 runLater. Une manière plus efficace de le faire serait d'ajouter les rectangles à un groupe non attaché au graphe de scène actif, puis d'ajouter le groupe au graphe de scène actif dans l'appel runLater. Par exemple:

final Group groupInSceneGraph = new Group(); 
Task<Void> task = new Task<Void>() { 
    @Override protected Void call() throws Exception { 
     final Group localGroup = new Group(); 
     for (int i=0; i<100; i++) { 
      if (isCancelled()) break; 
      final Rectangle r = new Rectangle(10, 10); 
      r.setX(10 * i); 

      localGroup.getChildren().add(r); 
     } 

     Platform.runLater(new Runnable() { 
      @Override public void run() { 
       groupInSceneGraph.add(localGroup); 
      } 
     }); 

     return null; 
    } 
}; 

Vous pouvez créer et modifier la plupart des objets de la scène graphique hors du fil d'application JavaFX (y compris le chargement FXML), tant que les objets ne sont pas attachés au graphe de scène active. Par graphe de scène actif, je veux dire un graphe de scène qui est actuellement attaché en tant que scène à une scène affichée. (Un contrôle complexe tel qu'un WebView peut être une exception à cette règle et peut nécessiter une création sur le thread d'application JavaFX).

Vous devez uniquement attacher les objets du graphe de scène créés à partir du fil d'application JavaFX au graphe de scène actif du fil d'application JavaFX (par exemple en utilisant Platform.runLater()). Et, vous devez travailler avec eux sur le thread d'application JavaFX tant qu'ils restent attachés au graphe de scène actif.

+0

Merci pour votre réponse. J'ai déjà essayé cette méthode. De cette façon, je peux afficher l'écran de démarrage et créer l'interface graphique, mais je ne peux pas mettre à jour la barre de progression. Voir mon message original pour le code exemple. – maumau