78

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

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

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

有任何想法吗?

4

4 回答 4

115

您可以从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.2FXMLLoader中得到了改进。

于 2012-05-25T11:01:34.240 回答
28

只是为了帮助澄清公认的答案,并可能为其他 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();
}

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

//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();
}
于 2017-02-06T16:45:15.080 回答
8

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

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));
}
于 2015-07-18T15:25:45.140 回答
3

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

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

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

于 2012-05-25T08:47:50.530 回答