【问题标题】:How to pass parameters to JavaFX application?如何将参数传递给 JavaFX 应用程序?
【发布时间】:2023-03-04 17:29:01
【问题描述】:

我正在像这样运行我的 JavaFX 应用程序:

public class MainEntry {
    public static void main(String[] args) {
        Controller controller = new Controller();
        Application.launch(MainStage.class);
    }
}

MainStage 类扩展 AppicationApplication.launch 在一个特殊的 FX 线程中启动我的 JavaFX 窗口,但在我的 main 方法中,我什至没有 MainStage 类的实例。

如何将非字符串参数(在我的例子中为 controller)传递给 MainStage 实例?这是一个有缺陷的设计吗?

【问题讨论】:

  • 为什么不能简单地在应用程序中实例化控制器?顺便提一句。 MainStage 似乎不是您的主应用程序的正确命名,因为 Stage 在 JavaFX 中具有不同的含义。

标签: java parameters javafx


【解决方案1】:

传递给main() 方法的String 数组是应用程序的参数,如果您随意选择使用JavaFX,则不是专门针对JavaFX 模块的。

最简单的解决方案是存储参数以供以后使用(例如,main() 方法旁边的静态属性,以及访问它的静态 getter 方法)。

【讨论】:

    【解决方案2】:

    问题 - 我

    我什至没有我的 MainStage 类的实例!

    解决方案

    您的 main 方法不需要 MainStage 的实例来调用您的 MainStage 的 start()。此工作由 JavaFX 启动器自动完成。

    来自文档

    JavaFX 应用程序的入口点是 Application 类。每当启动应用程序时,JavaFX 运行时都会按顺序执行以下操作:

    构造指定Application类的实例

    1. 调用 init() 方法
    2. 调用 start(javafx.stage.Stage) 方法
    3. 等待应用程序完成,当发生以下任一情况时会发生这种情况: 应用程序调用 Platform.exit() 最后一个窗口已关闭,Platform 上的implicitExit 属性为真
    4. 调用 stop() 方法

    Java 启动器加载并初始化指定的应用程序 JavaFX 应用程序线程上的类。如果没有 main 方法 Application 类,或者如果 main 方法调用 Application.launch(),然后是Application的一个实例 在 JavaFX 应用程序线程上构建。

    问题 - II

    如何将非字符串参数(在我的例子中为控制器)传递给 MainStage 实例?

    解决方案

    为什么需要将非字符串参数传递给MainStage?如果您需要一个控制器对象,只需从FXML 获取它

    示例

    public class MainEntry extends Application {
    
        @Override
        public void start(Stage stage) throws Exception {
            FXMLLoader loader = new FXMLLoader();
            Pane pane = (Pane) loader.load(getClass().getResourceAsStream("sample.fxml"));
            //Get the controller
            Controller controller = (Controller)loader.getController();
            Scene scene = new Scene(pane, 200, 200);
            stage.setScene(scene);
            stage.show();
        }
    
        public static void main(String[] args) {
            launch(args);// or launch(MainEntry.class)
        }
    }
    

    【讨论】:

    • 您能解释一下stage 参数是如何使用的吗?谁初始化它?你打电话给controller object是什么意思?谢谢和问候。
    • StageJavaFX launcher 初始化。它用于显示应用程序窗口。
    【解决方案3】:

    通常,除了传递给主应用程序的程序参数之外,不需要将参数传递给主应用程序。想要这样做的唯一原因是创建一个可重用的Application。但是Application 不需要是可重用的,因为它是组装您的应用程序的一段代码。将start 方法视为新的main

    因此,与其编写在main 方法中配置的可重用Application,不如应用程序本身作为配置器并使用可重用组件在start 方法中构建应用程序,例如:

    public class MyApplication extends Application {
    
        @Override
        public void start(Stage stage) throws Exception {
            // Just on example how it could be done...
            Controller controller = new Controller();
            MyMainComponent mainComponent = new MyMainComponent(controller);
            mainComponent.showIn(stage);
        }
    
        public static void main(String[] args) {
            Application.launch(args);
        }
    }
    

    【讨论】:

    • “唯一的原因......是创建一个可重用的应用程序”我认为还有其他原因,比如当你想要一个非 fx 应用程序启动时Application(对于示例 fx gui 添加到现有应用程序)。这样做时,非 fx 应用程序需要将信息传递给 Application
    • @c0der 我不同意。从非 fx Java 应用程序启动 fx 应用程序有两种方法:作为单独的进程或在同一个 VM 中。前者无论如何都不允许传递字符串/流以外的任何东西,因此不需要在那里有更丰富的 API。如果您想在同一个 VM 中启动它,您可以轻松地将自己的 Application 类编写为围绕可重用​​ UI 组件的“配置”包装器,如我的回答中所述。当然,如果必须在 Application 类中完成太多工作,这将不起作用。但这无论如何都是糟糕的设计。
    • 我不确定我是否遵循,但我认为我们同意可能需要将来自非 fx Java 应用程序的引用传递给 Application。或许你可以给this提供更好的答案
    【解决方案4】:

    这是我找到的一个很好的例子elsewhere

    @Override
    public void init () throws Exception
    {
      super.init ();
    
      Parameters parameters = getParameters ();
    
      Map<String, String> namedParameters = parameters.getNamed ();
      List<String> rawArguments = parameters.getRaw ();
      List<String> unnamedParameters = parameters.getUnnamed ();
    
      System.out.println ("\nnamedParameters -");
      for (Map.Entry<String, String> entry : namedParameters.entrySet ())
        System.out.println (entry.getKey () + " : " + entry.getValue ());
    
      System.out.println ("\nrawArguments -");
      for (String raw : rawArguments)
        System.out.println (raw);
    
      System.out.println ("\nunnamedParameters -");
      for (String unnamed : unnamedParameters)
        System.out.println (unnamed);
    }
    

    【讨论】:

      【解决方案5】:

      您可以在 MainStage 类中设置控制器。但是你必须做静态的,否则它会是空的。

      看看代码:

      public class MainEntry {
      
        public static void main(String[] args) {
          Controller controller = new Controller();
          MainStage ms = new MainStage();
          ms.setController(controller);
          Application.launch(MainStage.class, (java.lang.String[]) null);
        }
      

      }

      public class MainStage extends Application {
        private static Controller controller;
      
        public void start(Stage primaryStage) throws Exception {
          System.out.println(controller);
          primaryStage.show();
        }
      
        public void setController(Controller controller){
          this.controller = controller;
        }
      

      }

      【讨论】:

        【解决方案6】:

        当然,有必要也有可能将参数传递给 JavaFX 应用程序。

        我这样做是为了从不同的地方运行我的 JavaFX 客户端,这些地方需要不同的网络配置(直接或通过代理)。为了不立即更改代码,我实现了几个网络配置,可以在应用程序运行命令中使用 --configurationIndex=1 之类的参数进行选择。默认代码值为0。

        List<String> parameters;
        int parameterIndex;
        String parameter;
        
        parameters =
          getParameters().getRaw();
        
        for (parameterIndex = 0;
          parameterIndex < parameters.size();
          parameterIndex++) {
        
          parameter =
            parameters.get(
              parameterIndex);
        
          if (parameter.contains("configurationIndex")) {
            configurationIndex =
              Integer.valueOf(
                parameters.get(parameterIndex).
                split("=")[1]);
          }
        }
        

        在 Netbeans 中,您可以直接在项目中设置此参数以满足调试需要:项目 - 属性 - 运行 - 参数 - 将 --configurationIndex=1 插入字段。

        【讨论】:

          【解决方案7】:

          从 JavaFX 9 开始,您可以使用公共 API“手动”触发 JavaFX 平台的启动。唯一的缺点是stop 方法的调用方式与通过Application.launch 启动的应用程序不同:

          public class MainEntry {
              public static void main(String[] args) {
                  Controller controller = new Controller();
          
                  final MainStage mainStage = new MainStage(controller);
                  mainStage.init();
          
                  Platform.startup(() -> {
                      // create primary stage
                      Stage stage = new Stage();
          
                      mainStage.start(stage);
                  });
              }
          }
          

          传递给Platform.startupRunnable 在JavaFX 应用程序线程上被调用。

          【讨论】:

            【解决方案8】:

            案例 1 = java 标准类型 - 将它们作为 java 字符串“--name=value”传输,然后使用dmolony 的答案将它们转换为最终目的地

                      for ( Map.Entry<String, String> entry : namedParameters.entrySet ()){
                        System.out.println (entry.getKey() + " : " + entry.getValue ());              
                        switch( entry.getKey()){
                        case "media_url": media_url_received = entry.getValue(); break;
                        }
                  }
            

            参数在 Application.launch 中创建并在 init 中解码

            String args[] = {"--media_url=" + media_url, "--master_level=" + master_level};
            Application.launch( args);
            

            案例 2 = 如果您必须传输 java 对象,请使用此解决方法(这仅适用于一个 javafx 应用程序启动,如果您有复杂的案例,请创建一个解决方法映射并将索引作为字符串发送)

                public static Transfer_param javafx_tp;
            

            并在你的类初始化中将对象的实例设置为它自己的类中的静态

                Transfer_param.javafx_tp = tp1;
            

            现在您可以静态地找到您的最后一个对象,只使用一个 JavaFx 应用程序(请记住,如果您有很多 JavaFx 应用程序处于活动状态,您应该在 Map 或数组中发送一个带有静态变量标识的字符串,这样您就不会使用来自静态结构的假对象地址(使用此答案案例 1 中的示例来传输 --javafx_id=3 ...))

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 2012-12-24
              • 1970-01-01
              • 1970-01-01
              • 2020-04-29
              • 2021-01-10
              • 1970-01-01
              • 1970-01-01
              • 2015-01-04
              相关资源
              最近更新 更多