【问题标题】:Accessing FXML controller class访问 FXML 控制器类
【发布时间】:2023-03-19 11:58:02
【问题描述】:

我想随时与 FXML 控制器类进行通信,以从主应用程序或其他阶段更新屏幕上的信息。

这可能吗?我还没有找到任何方法。

静态函数可能是一种方式,但它们无法访问表单的控件。

有什么想法吗?

【问题讨论】:

    标签: javafx-2 fxml


    【解决方案1】:

    您可以从FXMLLoader获取控制器

    FXMLLoader fxmlLoader = new FXMLLoader();
    Pane p = fxmlLoader.load(getClass().getResource("foo.fxml").openStream());
    FooController fooController = (FooController) fxmlLoader.getController();
    

    将其存储在您的主阶段并提供 getFooController() getter 方法。
    从其他类或阶段,每次需要刷新加载的“foo.fxml”页面时,从其控制器询问它:

    getFooController().updatePage(strData);
    

    updatePage() 可以是这样的:

    // ...
    @FXML private Label lblData;
    // ...
    public void updatePage(String data){
        lblData.setText(data);
    }
    // ...
    

    在 FooController 类中。
    这样,其他页面用户就不会担心页面的内部结构,例如 Label lblData 是什么以及在哪里。

    另请查看https://stackoverflow.com/a/10718683/682495。在 JavaFX 2.2 中,FXMLLoader 得到了改进。

    【讨论】:

    • 我发现使用静态函数比这个解决方案更容易并且效果更好(至少对我而言)。能够访问控件的关键是拥有一个可以访问所有控件和公共方法的类的公共静态实例。
    • 我知道这是一个老问题......但任何人都可以提供关于答案的更多细节 w.r.t.前 3 行代码和 getFooController() 去哪儿了?
    • @adeena,FooController是你在“foo.fxml”中定义的控制器类,代码中没有getFooController()。
    • @UlukBiy 嗯......也许我正在尝试做一些与原始海报不同的事情。我在初级阶段有一个 FXML 应用程序和一个 TextArea。我想出了如何从其他 FXML 控制器访问它,但不是从我的包/项目中的任何其他类型的类。
    • @TannerSummers,一旦你得到了控制器实例,你需要把它放到一些公共的地方(把它想象成一个仓库),这样你的应用程序的其他类(模块)就可以访问它。 “主阶段”是指具有 JavaFX 应用程序入口点的类,即具有 start(Stage stage) 方法的类。在那个主类中,您可能更喜欢将控制器实例存储在某个集合中。或者创建一个新的 ControllerManager 类,它就像一个存储和访问它们的存储库。设计由您决定。
    【解决方案2】:

    只是为了帮助澄清已接受的答案,并可能为 JavaFX 新手节省一点时间:

    对于 JavaFX FXML 应用程序,NetBeans 将在主类中自动生成您的启动方法,如下所示:

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("FXMLDocument.fxml"));
    
        Scene scene = new Scene(root);
    
        stage.setScene(scene);
        stage.show();
    }
    

    现在,要访问控制器类,我们需要做的就是将 FXMLLoader load() 方法从静态实现更改为实例化实现,然后我们可以使用实例的方法来获取控制器,如下所示:

    //Static global variable for the controller (where MyController is the name of your controller class
    static MyController myControllerHandle;
    
    @Override
    public void start(Stage stage) throws Exception {
        //Set up instance instead of using static load() method
        FXMLLoader loader = new FXMLLoader(getClass().getResource("FXMLDocument.fxml"));
        Parent root = loader.load();
    
        //Now we have access to getController() through the instance... don't forget the type cast
        myControllerHandle = (MyController)loader.getController();
    
        Scene scene = new Scene(root);
    
        stage.setScene(scene);
        stage.show();
    }
    

    【讨论】:

      【解决方案3】:

      另一种解决方案是从您的控制器类中设置控制器,就像这样...

      public class Controller implements javafx.fxml.Initializable {
      
          @Override
          public void initialize(URL location, ResourceBundle resources) {
              // Implementing the Initializable interface means that this method
              // will be called when the controller instance is created
              App.setController(this);
          }
      
      }
      

      这是我更喜欢使用的解决方案,因为要创建一个功能齐全的 FXMLLoader 实例来正确处理本地资源等,代码有些混乱

      @Override
      public void start(Stage stage) throws Exception {
          Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml"));
      }
      

      @Override
      public void start(Stage stage) throws Exception {
          URL location = getClass().getResource("/sample.fxml");
          FXMLLoader loader = createFXMLLoader(location);
          Parent root = loader.load(location.openStream());
      }
      
      public FXMLLoader createFXMLLoader(URL location) {
          return new FXMLLoader(location, null, new JavaFXBuilderFactory(), null, Charset.forName(FXMLLoader.DEFAULT_CHARSET_NAME));
      }
      

      【讨论】:

      • 此解决方案也适用于 JavaFX 的早期版本 (
      • 总的来说,我认为选择的答案必须是首选的,虽然这是巧妙的:首先,你可以有多个控制器,所以你真的想在你的 Application 类中有一个静态地图, 关键控制器 --> 值加载器(注意你总是可以从加载器中获取控制器)。其次,我们得到了一个getController() 方法,所以使用它是有意义的。第三,当真正涉及实例操作时,应该避免使用static 方法,并且可能作为一般的编码偏好。
      • 将控制器存储在静态字段中不是一个好主意。
      【解决方案4】:

      在从主屏幕加载对象时,传递我找到并有效的数据的一种方法是使用查找,然后将数据设置在一个不可见的标签内,稍后我可以从控制器类中检索该标签。像这样:

      Parent root = FXMLLoader.load(me.getClass().getResource("Form.fxml"));
      Label lblData = (Label) root.lookup("#lblData");
      if (lblData!=null) lblData.setText(strData); 
      

      这可行,但必须有更好的方法。

      【讨论】:

        猜你喜欢
        • 2012-12-15
        • 2013-07-22
        • 1970-01-01
        • 2015-02-10
        • 2013-12-25
        • 2013-03-04
        • 2014-02-25
        • 1970-01-01
        相关资源
        最近更新 更多