我有一个使用预加载器的JavaFX应用程序。我想要做的是将其打包为本机包(Mac应用程序或包含Java JDK副本的Windows exe文件),以便那些在其计算机上没有正确版本的Java的用户仍然可以运行该应用程序。我已按照Oracles对creating native bundles和adding preloaders的说明进行操作。我得到的正是你所期望的 - 一个运行我程序的本机包。
问题是捆绑包完全忽略了我的预加载器。它只运行主程序(经过很长的加载时间)。我知道包含了预加载器,因为当我单独运行jar文件时,它会显示出来。
是否有人成功将JavaFX应用与预加载器捆绑在一起?你能指导我怎么做吗?我使用的是Netbeans。
编辑:
这是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());
}
}
}
这是我主程序的第一部分:
@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();
}
答案 0 :(得分:3)
此示例仅适用于安装程序exe / msi / image(没有Mac来测试dmg)。这一步一步假设您已经安装了所需的工具,如InnoSetup,Wix Toolset等。它还假设您已经配置了使用netbeans运行的工具(设置路径,编辑配置文件等)。
我在Netbeans中创建了一个新的JavaFX应用程序项目,如下所示:
然后我给了项目一个名字并说,该向导应该创建一个具有给定名称的预加载器项目。另外,它应该在给定的包名中创建一个应用程序类。
之后我右键单击了应用程序项目并在部署中选择"启用Native Native"。
在第4步中,我已经为应用程序创建了代码。预加载器将在init()方法中更新,并且仅在那里更新。你应用程序初始化的所有工作都应该放在这里。
<强> 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);
}
}
唯一缺少的部分是预加载器代码。寻找唯一需要的方法handleApplicationNotification,所有其他方法,如 handleProgressNotification 或 handleStateChangeNotification ,您可以安全地删除,或使它们成为空的存根。
<强> 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();
}
}
}
}
现在是时候将应用程序捆绑到本机包(仅图像/ exe / msi)。我右键单击了applicaton项目并选择了逐个创建的包。
选择打包为图像后,您的目录应如下所示:
在深入挖掘目录后,您应该找到图像:
双击.exe文件应启动您的应用程序:
你可以做的最大的错误是,在你的应用程序启动方法中调用东西。 Normaly都必须在应用程序初始化方法中完成,在那里加载巨大的文件,在那里你将连接到数据库,或者在那里加载一个包含大量css或fxml文件的巨大自定义布局。并且有一个地方可以向预加载器说再见(进度= 1)。尽量不要在应用程序启动方法中的预加载器上执行操作。不要在线程中思考,预加载器是在显示主阶段之前做的事情,所以按顺序加载。