为具有预加载器的JavaFX应用程序创建本机包 [英] Create a native bundle for a JavaFX application that has a preloader

查看:264
本文介绍了为具有预加载器的JavaFX应用程序创建本机包的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个使用预加载器的JavaFX应用程序。我想要做的是将其打包为本机包(Mac应用程序或包含Java JDK副本的Windows exe文件),因此在其计算机上没有正确版本的Java的用户仍然可以运行应用程序。我已按照Oracles的说明创建本机包和对于添加预加载器。我得到的正是你所期望的 - 一个运行我程序的本机包。

I have a JavaFX application that uses a preloader. What I'd like to do is package it up as a native bundle (Mac app or Windows exe file that contains a copy of the Java JDK) so users who don't have the right version of Java on their computers can still run the app. I've followed Oracles instructions for creating native bundles and for adding preloaders. What I get is exactly what you'd expect—a native bundle that runs my program.

问题是捆绑包完全忽略了我的预加载器。它只运行主程序(经过很长的加载时间)。我知道包含了预加载器,因为当我单独运行jar文件时,它会显示出来。

The problem is that the bundle completely ignores my preloader. It just runs the main program (after a long load time). I know the preloader is included because, when I run the jar file alone, it shows up.

是否有人成功地将JavaFX应用程序与预加载器捆绑在一起?你能指导我怎么做吗?我正在使用Netbeans。

Has anyone successfully bundled a JavaFX app with a preloader? Can you guide me through how to do so? I'm using Netbeans.

编辑:

这是Preloader:

Here is the Preloader:

import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.stage.Stage;
import javafx.stage.StageStyle;

public class Splash extends Preloader {

    ProgressIndicator bar;
    ImageView Background;
    Stage stage;

    private Scene createPreloaderScene() {
        bar = new ProgressIndicator();
        bar.setLayoutX(380);
        bar.setLayoutY(250);
        bar.setPrefSize(60, 60);

        Background = new ImageView("Images/Splash.png");
        Background.setEffect(null);

        Pane p = new Pane();
        p.setStyle("-fx-background-color: transparent;");
        p.getChildren().addAll(Background, bar);

        Scene scene = new Scene(p, 794, 587);      
        scene.setFill(null);
        scene.getStylesheets().add(Scrap2.class.getResource("CSS/Progress.css").toExternalForm());
        bar.setId("myprogress");
        return scene;
    }

    @Override
    public void start(Stage stage) throws Exception {
        this.stage = stage;
        stage.setScene(createPreloaderScene());    
        stage.initStyle(StageStyle.TRANSPARENT);
        stage.show();
    }

    @Override
    public void handleStateChangeNotification(StateChangeNotification scn) {
        if (scn.getType() == StateChangeNotification.Type.BEFORE_START) {
            stage.hide();
        }
    }

    @Override
    public void handleProgressNotification(ProgressNotification pn) {
        bar.setProgress(pn.getProgress());
    }    

    @Override
   public void handleApplicationNotification(PreloaderNotification arg0) {
          if (arg0 instanceof ProgressNotification) {
             ProgressNotification pn= (ProgressNotification) arg0;
             bar.setProgress(pn.getProgress());
          }
    }

}

在这里是我主程序的第一部分:

And here is the first part of my main program:

@Override
public void init(){

    /*Root*/
    root = new Pane();
    root.setStyle("-fx-background-color: transparent;");
    root.setLayoutX(150);

    notifyPreloader(new Preloader.ProgressNotification(0.1));

    /*Create Background*/
    createBinding(stage);
    createContents();
    createSaveMessages();
    createFlipBook();

    notifyPreloader(new Preloader.ProgressNotification(0.2));

    /*Add Pages*/
    createOverview();
    createAccounts();
    notifyPreloader(new Preloader.ProgressNotification(0.3));
    createCounselors();
    createInsurance();
    notifyPreloader(new Preloader.ProgressNotification(0.4));
    createAssets();
    createPapers();
    notifyPreloader(new Preloader.ProgressNotification(0.5));
    createLoans();
    createFuneral();
    notifyPreloader(new Preloader.ProgressNotification(0.6));
    createWills();
    addAllPages();
    notifyPreloader(new Preloader.ProgressNotification(0.7));

    /*Add Toolbar on top*/
    createToolBar();
    notifyPreloader(new Preloader.ProgressNotification(0.9));

    /*Create Opening Instructions*/
    opening();

    /*Load Saved Data*/
    load();
    notifyPreloader(new Preloader.ProgressNotification(1.0));


}

@Override
public void start(Stage stage) {
    /*Scene*/
    scene = new Scene(root, 1200, 700);
    stage.setScene(scene);
    scene.setFill(null);

    /*Stage*/
    this.stage = stage;
    stage.initStyle(StageStyle.TRANSPARENT);
    stage.centerOnScreen();
    stage.show();
}


推荐答案

此示例适用于安装程序仅限exe / msi / image(没有Mac来测试dmg)。这一步一步假设您已经安装了所需的工具,如InnoSetup,Wix Toolset等。它还假设您已经配置了使用netbeans运行的工具(设置路径,编辑配置文件等)。

This example will work with installers exe/msi/image only (have no Mac to test dmg). This step by step assumes, that you already installed the needed tools like InnoSetup, Wix Toolset, etc. It also assumes, that you have configured the tools to run with netbeans (setting paths, edit config files, etc.).

我在Netbeans中创建了一个新的JavaFX应用项目,如下所示:

I've made a new JavaFX Application Project in Netbeans like this:

然后我给了项目一个名字,说,向导应该用gi创建一个preloader项目还有名字。另外,它应该在给定的包名中创建一个应用程序类。

Then I gave the project a name and said, that the wizard should create a preloader project with the given name too. Additionally it should create an application class in given package name.

之后我右键单击应用程序项目并在部署下选择启用原生包装。

After that I right clicked on the application project and select under deployment "Enable Native Packaging".

在步骤4中,我为应用程序创建了代码。预加载器将在init()方法中更新,并且仅在那里更新。你在初始化应用程序的所有工作都应该放在这里。

In step 4 I've created the code for the application. The preloader will be updated in the init() method and only there. All your work for initialization the application should go here.

JavaFXPreloaderApp.java

import javafx.application.Application;
import javafx.application.Preloader;
import javafx.event.ActionEvent;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class JavaFXPreloaderApp extends Application {

  @Override
  public void start(Stage primaryStage) {
    Scene scene = new Scene(createContent(), 300, 250);
    primaryStage.setTitle("Hello World!");
    primaryStage.setScene(scene);
    primaryStage.show();
  }

  public Parent createContent() {
    Button btn = new Button();
    btn.setText("Say 'Hello World'");
    btn.setOnAction((ActionEvent event) -> {
      System.out.println("Hello World!");
    });

    StackPane root = new StackPane();
    root.getChildren().add(btn);
    return root;
  }

  @Override
  public void init() throws Exception {
    // A time consuming task simulation
    final int max = 10;
    for (int i = 1; i <= max; i++) {
      notifyPreloader(new Preloader.ProgressNotification(((double) i) / max));
      Thread.sleep(500);
    }
  }

  /**
   * @param args the command line arguments
   */
  public static void main(String[] args) {
    launch(args);
  }
}



第5步:



唯一缺少的部分是预加载器代码。寻找唯一需要的方法handleApplicationNotification,所有其他方法,如 handleProgressNotification handleStateChangeNotification ,你可以安全地删除,或使它们成为空的存根。

Step 5:

The only missing part was the preloader code. Look for the only needed method handleApplicationNotification, all the other methods, like handleProgressNotification or handleStateChangeNotification, you can safely delete, or make them empty stubs.

JavaFXPreloader.java

import javafx.application.Preloader;
import javafx.application.Preloader.ProgressNotification;
import javafx.application.Preloader.StateChangeNotification;
import javafx.scene.Scene;
import javafx.scene.control.ProgressBar;
import javafx.scene.layout.BorderPane;
import javafx.stage.Stage;

/**
 * Simple Preloader Using the ProgressBar Control
 */
public class JavaFXPreloader extends Preloader {

  ProgressBar bar;
  Stage stage;

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

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

  @Override
  public void handleApplicationNotification(PreloaderNotification info) {
    // Check if info is ProgressNotification
    if (info instanceof ProgressNotification) {
      // if yes, get the info and cast it
      ProgressNotification pn = (ProgressNotification) info;
      // update progress
      bar.setProgress(pn.getProgress());
      // if this was the last progress (progress reached 1), hide preloader
      // this is really important, if preloader isn't hide until app loader
      // reaches the start method of application and tries to open the stage of
      // the main app with the show() method, it will not work.
      if (pn.getProgress() == 1.0) {
        stage.hide();
      }
    }
  }
}



步骤6:



现在是时候将应用程序捆绑到本机包(仅图像/ exe / msi)。我右键单击了applicaton项目并选择了逐个创建的包。

Step 6:

Now it was time to bundle the application to native packages (image only/exe/msi). I right clicked on the applicaton project and selected the packages to create one by one.

选择打包后只作为图像目录应如下所示:

After choosen to package as image only your directory should look like this:

深入挖掘目录后,您应找到图像:

After digging deeper in your directory you should find the image:

双击.exe文件应该启动你的应用程序:

A double click on the .exe file should start your application:

你可以做的最大的错误是,在你的应用程序启动方法中调用东西。 Normaly都必须在应用程序初始化方法中完成,在那里加载巨大的文件,在那里你将连接到数据库,或者在那里加载一个包含大量css或fxml文件的巨大自定义布局。并且有一个地方可以向预加载器说再见(进度= 1)。尽量不要在应用程序启动方法中的预加载器上执行操作。不要在Thread中考虑,预加载器是在显示主阶段之前做的事情,所以按顺序加载。

The biggest mistake you could do is, to call things in your application start methods. Normaly all have to be done in the application init method, there you load the huge files, there you will connect to the db, or there you load a huge custom layout with a lot of css or fxml files. And there is the place to say good bye to the preloader (progress = 1). Try not to do things at the preloader in your application start method. Don't think in Thread's, the preloader is there to do things before the main stage is shown, so load all in sequence.

这篇关于为具有预加载器的JavaFX应用程序创建本机包的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆