2017-06-06 3 views
0

Mon IDE est IntelliJ. J'ai essayé le document this pour apprendre le preloader mais pour une raison quelconque, le preloader n'est jamais appelé depuis ma classe principale, ou même ses méthodes sont appelées.JavaFX Preloader n'a jamais été appelé par le principal

Voici donc ma classe principale:

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); 
       notifyPreloader(new ProgressNotification(((double) i)/max)); 
      } 
      ready.setValue(Boolean.TRUE); 

      notifyPreloader(new StateChangeNotification(
       StateChangeNotification.Type.BEFORE_START)); 
      return null; 
     }}; 
    new Thread(task).start(); 
} 

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

@Override 
public void start(final Stage stage) throws Exception { 
    longStart(); 
    stage.setScene(new Scene(new Label("Application started"),400, 400)); 
    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(); 
         }});}}});;}} 

Et ma classe de préchargement:

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) { 
    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) { 
     double v = ((ProgressNotification) pn).getProgress(); 
     if (!noLoadingProgress) {   
      v = 0.5 + v/2; 
     } 
     bar.setProgress(v);    
    } else if (pn instanceof StateChangeNotification) { 
     stage.hide(); 
    } 
} 
} 

Vous pouvez vérifier http://docs.oracle.com/javafx/2/deployment/preloaders.htm documents aussi. Ces codes appartiennent à l'exemple 9-11 et 9-12.

+0

Où chargez-vous le «Preloader»? Jetez un oeil à https://stackoverflow.com/questions/43551620/javafx-preloader-thread/43554718#43554718 – jns

+0

Comment exécutez-vous l'application? Il doit être empaqueté avec le préchargeur spécifié (ou utiliser des classes d'API non publiques pour le lancement, comme dans la question ci-dessus). Exécuter simplement la classe principale ici ne provoquera pas le chargement du préchargeur. –

+0

Je pensais que je lancerais quand j'utiliser la méthode notifyPreloader. Je dois le lancer comme "LauncherImpl.launchApplication (App.class, TestPreloader.class, args);" ? –

Répondre

0

Vous devez spécifier la classe de préchargement à l'application lors de son lancement. Une façon «rapide et sale» de faire cela est d'utiliser la classe d'API non publique com.sun.javafx.application.LauncherImpl. Notez que cette classe n'est pas garantie d'être disponible dans les futures versions de JavaFX, et donc vous ne devriez l'utiliser que pour un test rapide (voire pas du tout). Utilisez la méthode principale suivante dans votre classe LongInitApp:

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

Le « officiel » d'inclure un préchargement est en le précisant dans le cadre du processus de déploiement JavaFX. La documentation complète du processus de déploiement est au http://docs.oracle.com/javase/8/docs/technotes/guides/deploy/, mais une approche minimale est la suivante.

  1. compiler l'application (votre IDE sera généralement faire lorsque vous enregistrez de toute façon)
  2. A partir de la ligne de commande, exécutez l'outil javapackager avec la commande createjar:

    javapackager -createjar -outfile myapp.jar -appclass my.package.LongInitApp \ 
        -preloader my.package.LongAppInitPreloader -srcdir dir 
    

    my.package est le package contenant vos classes application et preloader (celles-ci peuvent être dans des packages différents) et dir est la racine de la structure du répertoire contenant toutes vos classes (par exemple si my.package était vraiment le nom de votre package, le n dir aurait un sous-répertoire my, qui aurait un sous-répertoire package, qui contiendrait les fichiers .class).

    Cela va générer un fichier myapp.jar qui est exécutable et conscient de votre préchargeur, vous pouvez donc l'exécuter avec java -jar myapp.jar. Si vous êtes intéressé, vous pouvez extraire le manifeste généré à partir du fichier jar et voir ce qu'il contient avec jar xf myapp.jar META-INF/MANIFEST.MF (puis afficher le fichier META-INF/MANIFEST.MF). (En bref, la classe principale est une classe interne conçue pour lancer une application JavaFX Le fichier manifeste contient des propriétés spécifiant la classe d'application JavaFX (LongInitApp dans votre cas) et la classe preloader, le cas échéant. classe interne qui lance l'application récupère ces propriétés et sa principale méthode lance essentiellement l'application que vous avez défini, en utilisant le préchargement si elle est là.)

    Notez votre classe d'application LongInitApp n'a pas besoin (et probablement ne devrait pas avoir) une méthode main si vous utilisez cette approche.

La plupart des EDI ont une forme de support pour cela. Par exemple. Si vous utilisez Eclipse avec le plugin E (fx) clipse et créez un projet JavaFX, il génèrera un fichier build.fxbuild pour vous. Double-cliquez sur ce fichier pour ouvrir un éditeur visuel dans lequel vous pouvez définir les propriétés définies dans la commande javapackager ci-dessus. Cliquer sur "Générer ant build.xml et lancer" créera ensuite le fichier jar.

À moins d'avoir besoin de la fonctionnalité spécifique fournie par un préchargeur, au-delà de ce que vous pouvez facilement programmer vous-même, cela ne vaut pas la peine de le faire. En particulier, un préchargement est particulièrement utile si vous déployez votre application via Java Web Start, et que le téléchargement du fichier jar principal prendra beaucoup de temps. Le préchargement peut être montré pendant que cela se produit. Si vous utilisez une application autonome (ou un package d'application autonome), vous pouvez créer facilement la fonctionnalité "préchargeur" ​​vous-même.

Par exemple, à moins que j'utilisais Java Web Start et le fichier principal du pot étaient grandes, je ne serais probablement Refactor votre code d'exemple en faisant le « préchargement » juste une classe ordinaire ancienne:

import javafx.scene.Scene; 
import javafx.beans.property.DoubleProperty ; 
import javafx.scene.control.ProgressBar; 
import javafx.scene.layout.BorderPane; 
import javafx.stage.Stage; 

public class LongAppInitPreloader { 
    private ProgressBar bar; 

    private Stage stage; 

    public LongAppInitPreloader() { 
     this.stage = new Stage(); 
     stage.setScene(createPreloaderScene()); 
    } 

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

    public void show() { 
     stage.show(); 
    } 

    public void hide() { 
     stage.hide(); 
    } 

    public DoubleProperty progressProperty() { 
     return bar.progressProperty(); 
    } 
} 

puis votre classe d'application peut simplement utiliser une tâche et mettre à jour sa progression:

import javafx.application.Application; 
import javafx.concurrent.Task; 
import javafx.scene.Scene; 
import javafx.scene.control.Label; 
import javafx.stage.Stage; 

public class LongInitApp extends Application { 

    @Override 
    public void start(final Stage stage) throws Exception { 
     Task<Void> task = createLongStartTask(); 

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

     LongAppInitPreloader preloader = new LongAppInitPreloader(); 
     preloader.progressProperty().bind(task.progressProperty()); 

     task.setOnSucceeded(e -> { 
      stage.show(); 
      preloader.hide(); 
     }); 
     preloader.show(); 

     new Thread(task).start(); 
    } 

    private Task<Void> createLongStartTask() { 
     // simulate long init in background 
     Task<Void> task = new Task<Void>() { 
      @Override 
      protected Void call() throws Exception { 
       int max = 10; 
       for (int i = 1; i <= max; i++) { 
        Thread.sleep(200); 
        updateProgress(i, max); 
       } 

       return null; 
      } 
     }; 
     return task ; 
    } 

    // just here so I can run directly from Eclipse: 
    public static void main(String args[]) { 
     launch(args); 
    } 
} 
+0

Merci l'homme, mais après votre commentaire j'ai changé d'avis mon application est beaucoup trop simple pour précharge. J'ai donc essayé la méthode thread.start() mais attend toujours que la première application continue. Puis j'ai essayé comme ci-dessous: –

+0

J'ai essayé Platform.runlater pour exécuter une classe simpleLoader, avant une boucle for et après la boucle. La boucle est juste là pour simuler un progrès. Ce que je veux, c'est quand il est dans la boucle for sp (simpleLoader) devrait être vu comme le chargement de l'animation. Mais à la place, il ouvre le sp mais ne charge aucun nœud à l'intérieur (il contient une barre et une étiquette) et se ferme après la boucle for. Qu'est-ce que je fais mal? –

+0

Pourquoi lancez-vous le "chargeur simple" sur le fil d'application Fx? Cela empêchera l'interface utilisateur de mettre à jour jusqu'à ce qu'il soit terminé. –

1

Il vous manque méthode Main dans la classe LongInitApp

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

J'ai ajouté que rien n'a changé. –