【问题标题】:JavaFX launch Application standalone OR from another applicationJavaFX 独立启动应用程序或从另一个应用程序启动
【发布时间】:2014-11-05 12:36:30
【问题描述】:

以下场景:

JavaFxMainApp JavaFXUpdaterApp

两者都是带有 GUI 和 void main() 方法的 JavaFX 应用程序。

  1. 更新程序必须能够通过访问来启动 JavaFXMainApp JavaFxMainApp.jar 只知道主类-> 它只能!称呼 main().

  2. JavaFxMainApp 还必须能够独立运行,方法是启动 main().

我无法启动多个 VMS,并且这两个应用程序无法通信。

这个问题是:

Application.launch() 每个 JVM 只能执行一次。

启动应用的标准 javaFx 方式:

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

这里不可能满足要求 1)。由于两个 main() 方法都调用了 launch()。

我发现的第二种方法是:

Updater + MainApp
 public static void main(String[] args) {
        Application app2 = JavaFxMainApp.class.newInstance(); 
        Stage anotherStage = new Stage();
        app2.start(anotherStage);
}

首先,我失去了传递参数的可能性,但我可以忍受,因为无论如何它们都不会被使用。 这里的主要问题是,该代码仅在 JVM 已经运行 JavaFx 线程时才有效,因此它要求之前在 JVM 中调用了 launch()。情况并非如此,因为这两个调用都不再调用 launch()。

混合方法:

Updater calls launch(), MainApp takes the second approach

无法满足要求 2),因为现在无法在没有启动器更新程序的情况下启动 MainApp。

我的另一个想法是“尝试启动()catch()->在两个应用程序中尝试第二种方法(),但这会将两个应用程序结合起来并降低设置的灵活性。

有没有一种方法可以实现这一点,而不必重写 JavaFxs 的 LauncherImpl 或 Application 类来满足这些需求?

【问题讨论】:

  • 为什么更新程序只能调用main(...)?另外,您能否澄清一下更新程序在什么情况下“调用”主应用程序?更新程序是否已经在运行(作为 GUI 应用程序)?用例不是很清楚。
  • 更新程序只能调用 main,因为它必须能够管理任何 Java 应用程序而无需进行调整。这样它就可以启动任何具有 main() 方法的 java 应用程序。更新程序搜索新版本并可以在线程中启动 MainApp。原因和规范是多个无聊的页面,恐怕不是我的发布。不是我的想法,但我将不得不接受所做的决定:/
  • 这些要求确实与 JavaFX 的设计方式不一致。例如,在 Java 8 中,JavaFX 应用程序甚至根本不需要 main 方法 - 因此在 Java 8 中,所有 Java 应用程序都具有 main 方法的规则存在例外情况。
  • 添加了建议的 hack。

标签: java javafx


【解决方案1】:

你可以这样做吗:

public class MainApp extends Application {

    private Parent uiContent ;

    public static final double DEFAULT_WIDTH = 800 ;
    public static final double DEFAULT_HEIGHT = 600 ;

    public Parent getContent() {
        if (uiContent == null) {
            uiContent = initializeUI();
        }
        return uiContent ;
    }

    public Scene createScene() {
        return new Scene(getContent(), DEFAULT_WIDTH, DEFAULT_HEIGHT);
    }

    public void initializeAndShowStage(Stage stage) {
        stage.setScene(createScene());
        stage.show();
    }

    private Parent initializeUI() {
        // probably wise to check we are on the FX Application thread here...
        Pane root = ... ;
        // build ui....
        return root ;
    }

    @Override
    public void start(Stage primaryStage) throws Exception {
        initializeAndShowStage(primaryStage);
    }

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

public class UpdaterApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        // whatever you need to launch the updater app here...

    }

    // invoke from the FX Application Thread to "start" main app:
    private void showMainApp(Stage stage) {
        MainApp app = new MainApp();
        app.initializeAndShowStage(stage);
    }

    private void showMainApp() {
        showMainApp(new Stage());
    }

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

这将是更受欢迎的方法。如果您的要求迫使您致电main,那么您可以尝试以下方式:

public class MainApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        // .... build UI etc
    }

    public static void main(String[] args) throws Exception {
        if (Platform.isFXApplicationThread()) {
            Stage someStage = new Stage();
            MainApp app = new MainApp();
            app.start(stage);
        } else {
            launch(args);
        }
    }
}

然后您的更新程序应用可以从 FX 应用程序线程调用 MainApp().main(new String[0]));

这感觉有点像 hack。

【讨论】:

  • MainApp app = new MainApp(); app.initializeAndShowStage(舞台);这部分与“唯一可以调用的”部分相矛盾
  • “hack”也是我自己想出来的(非常相似,如果启动失败,我用 start() 添加了重试)。我知道,显然它并没有缩进使用 fx 做这种事情,而是决定只将更新程序显示为 swingUI,因为它只是显示下载进度的进度条。不干净,但它可以工作,而且不那么黑客。无论如何,感谢您确认使用“通用” javafx 方法是不可能的
【解决方案2】:

您希望自己的 MainApp 启动,并且您还希望 UpdateApp 在需要时启动 MainApp,那么您可以按照我的步骤操作。我试过了,这个模型很有效。

这是起点。你需要调用这个类来开始你的应用程序

public class StartAnApp {
    public static void main(String[] args){
        new Thread(new MainApp()).start(); // this will call your MainApp 
    }
}

这是将启动的第一个应用程序。要启动 JavaFX 应用程序,您需要有一个 main() 方法。所以确保在这个类中提供一个main方法。

public class MainApp extends Application implements Runnable{
    public MainApp(){}  // constructor

    @Override
    public void start(Stage stage){
        Text text = new Text("MainApp");
        Button startUpdate = new Button("Start Update");

        // When this button is pressed. It will launch UpdateApp Application
        startUpdate.setOnAction( e -> {
            Platform.runLater(new Runnable(){
                @Override
                public void run(){
                    new UpdateApp().start(new Stage());
                }
            });
        });

        Group root = new Group(text);
        Scene scene = new Scene(root,300,400);
        stage.setScene(scene);
        stage.setX(0);
        stage.setY(0);
        stage.show();
    }

    // This method will be used when you first start an Application for
    // which main method is required
    public static void main(String[] args){
        launch(args);
    }

    // This will be used when you call this Application from another JavaFX application
    // if you have closed this application before
    @Override
    public void run(){
        launch();
    }
}

这是您的 UpdateApp。此方法没有 main() 方法。

public class UpdateApp extends Application implements Runnable{
    public UpdateApp(){}  // constructor

    @Override
    public void start(Stage stage){
        Text text = new Text("UpdateApp");
        Button startAnother = new Button("Start Another");

        // When this button is pressed. It will launch MainApp Application or you can add any other JavaApplication
        startAnother.setOnAction( e -> {
            Platform.runLater(new Runnable(){
                @Override
                public void run(){
                    new MainApp().start(new Stage());
                }
            });
        });

        Group root = new Group(text);
        Scene scene = new Scene(root,300,400);
        stage.setScene(scene);
        stage.setX(350);
        stage.setY(0);
        stage.show();
    }

    // This will be used when you call this Application from another JavaFX application
    @Override
    public void run(){
        launch();
    }
}

【讨论】:

    猜你喜欢
    • 2013-03-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-17
    • 1970-01-01
    • 2012-02-03
    相关资源
    最近更新 更多