JavaFX Preloader从未从main调用过

时间:2017-06-06 11:55:26

标签: java intellij-idea javafx javafx-2 javafx-8

我的IDE是IntelliJ。我尝试了this文档来学习预加载器,但出于某种原因,预加载器永远不会从我的主类调用,甚至调用它的方法。

所以这是我的主要课程:

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();
                        }});}}});;}}

我的预加载器类:

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();
    }
}  
 }

您也可以查看此http://docs.oracle.com/javafx/2/deployment/preloaders.htm文档。此代码属于示例9-11和9-12。

2 个答案:

答案 0 :(得分:2)

您需要在启动时为应用程序指定预加载器类。 A&#34;快速而肮脏&#34;这样做的方法是使用非公共API类com.sun.javafx.application.LauncherImpl。请注意,此类不保证在将来的JavaFX版本中可用,因此您应该仅使用它来进行快速测试(如果有的话)。在LongInitApp课程中使用以下主要方法:

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

&#34;官方&#34;包含预加载器的方法是将其指定为JavaFX部署过程的一部分。部署过程的完整文档位于http://docs.oracle.com/javase/8/docs/technotes/guides/deploy/,但最小化方法如下。

  1. 编译应用程序(无论如何,您的IDE通常会执行此操作)
  2. 从命令行,使用javapackager命令运行createjar工具:

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

    其中my.package是包含应用程序和预加载器类的包(这些类可以在不同的包中),dir是包含所有类的目录结构的根(例如my.package确实是你的包名,然后dir将有一个子目录my,它有一个子目录package,它将包含.class个文件。

    这将生成一个myapp.jar文件,该文件可执行并且知道您的预加载器,因此您可以使用java -jar myapp.jar执行它。如果您有兴趣,可以从jar文件中提取生成的清单,并使用jar xf myapp.jar META-INF/MANIFEST.MF查看其中的内容(然后查看文件META-INF/MANIFEST.MF)。 (简而言之,它的作用是将主类声明为一个旨在启动JavaFX应用程序的内部类。清单文件包含指定JavaFX应用程序类(在您的情况下为LongInitApp)和预加载器类的属性,如果一个存在。启动应用程序的内部类检索这些属性,它的主要方法基本上启动你定义的应用程序,如果它在那里使用预加载器。)

    如果您使用此方法,请注意您的应用程序类LongInitApp不需要(并且可能不应该main方法。

  3. 大多数IDE都有某种形式的支持。例如。如果你将Eclipse与E(fx)clipse插件一起使用,并创建一个JavaFX项目,它将为你生成一个build.fxbuild文件。双击该文件将打开一个可视编辑器,您可以在其中设置上面javapackager命令中定义的属性。单击&#34;生成ant build.xml并运行&#34;然后将创建jar文件。

    除非您需要预加载器提供的特定功能,除了您可以轻松编程的功能之外,还可能不值得花费这些功能。具体来说,如果您通过Java Web Start部署应用程序,预加载器特别有用,并且主jar文件的下载将花费很长时间。正在发生时,可以显示预加载器。如果您使用的是独立应用程序(或独立的应用程序包),那么您可以非常轻松地创建&#34; preloader&#34;功能你自己。

    例如,除非我使用Java Web Start并且主jar文件很大,否则我可能会通过制作&#34; preloader&#34;来重构您的示例代码。只是一个普通的老班:

    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();
        }
    }
    

    然后您的应用程序类可以使用任务并更新其进度:

    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);
        }
    }
    

答案 1 :(得分:0)

您缺少LongInitApp类中的Main方法

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