如何从JavaFX中的另一个控制器类访问UI元素?

ade*_*ena 12 java javafx java-8 fxml

我有一个用NetBeans 8编写的JavaFX/Java 8应用程序(否SceneBuilder).

我的应用程序有一个主窗口,它有自己的FXML文件(primary.fxml)和它自己的控制器类(FXMLPrimaryController.java).FXML中的一个项目是TextArea.FXMLPrimaryController.java中的一些方法是关于附加的TextArea.

此应用程序现在生成第二个窗口(另一个"阶段"),其中包含自己的FXML(second.fxml)和自己的控制器类(FXMLsecondController.java).

在第二个控制器类中,如何访问主要的TextArea?

以下是相关代码的示例:

primary.fxml:

<Button text="press me!" onAction="#openSecondWindow" />
<TextArea fx:id="myArea" />
Run Code Online (Sandbox Code Playgroud)

FXMLPrimaryController.java:

public class FXMLPrimaryController implements Initializable {

    @Override
    public void initialize(URL url, ResourceBundle rb) {
    }

    @FXML private TextArea myArea;

    final public void writeToTextArea() {
        myArea.appendText("hi!");
    }

    @FXML
    private void openSecondWindow(ActionEvent event) throws Exception {

        Group root = new Group();
        Stage stage = new Stage();

        AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
        root.getChildren().add(frame);
        Scene scene = new Scene(root);

        stage.setScene(scene);
        stage.show();
    }

}
Run Code Online (Sandbox Code Playgroud)

second.fxml没什么特别的.假设有一个按钮onAction="#writeSomething".

在FXMLsecondController.java中,我想要一个引用上面的函数TextArea.

Rai*_*rze 12

为辅助控制器加载FXML时,请执行以下操作:

FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("second.fxml"));
AnchorPane frame = fxmlLoader.load();
FXMLSecondaryController c = (FXMLSecondaryController) fxmlLoader.getController();
Run Code Online (Sandbox Code Playgroud)

然后,您可以将引用传递给第二个控制器.这可能只是TextArea.

编辑:

load()在上面的代码段中替换了呼叫并添加了setLocation()呼叫.旧线路AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));是错误的,因为它称为静态load功能,这在这里没用.

编辑:

(更改了上面的代码段以更好地匹配您的变量名称.)上面的代码段替换了您的代码的这一部分:

AnchorPane frame = FXMLLoader.load(getClass().getResource("second.fxml"));
Run Code Online (Sandbox Code Playgroud)

该行使用FXMLLoader加载视图,并创建控制器的实例 - 在本例中FXMLSecondaryController.但是,你不能使用静态FXMLLoader.load方法,你需要一个实例FXMLLoader.该实例在加载后保存对控制器的引用,您可以使用它来检索它getController().并且您需要将返回的值强制转换为控制器类(with (FXMLSecondaryController)).

您的主控制器有一个字段:

@FXML private TextArea myArea;
Run Code Online (Sandbox Code Playgroud)

它包含对您的引用,TextArea并由fxml加载器初始化.(如果删除@FXML注释,加载程序将不会触及它.)

在辅助控制器中,添加以下字段:

public TextArea primaryTextArea;
Run Code Online (Sandbox Code Playgroud)

注意,@FXML它已经消失(fxml加载器不会触及该字段)以及private(您想要设置字段,因此其他人必须看到它).现在,您可以在加载控制器后设置此字段.所以回到加载代码:

FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("second.fxml"));
AnchorPane frame = fxmlLoader.load();
FXMLSecondaryController c = (FXMLSecondaryController) fxmlLoader.getController();
// Add this too:
c.primaryTextArea = myArea;
Run Code Online (Sandbox Code Playgroud)

编辑:替换load()上面代码段中的setLocation()呼叫并添加了呼叫.旧线路AnchorPane frame = fxmlLoader.load(getClass().getResource("second.fxml"));是错误的,因为它称为静态load功能,这在这里没用.

FXMLSecondaryController现在具有与一个参考TextArea主控制器.在其中一种方法中,您应该能够访问其内容:

public class FXMLSecondaryController implements Initializable {
    // ...

    public TextArea primaryTextArea;

    // ...

    @FXML
    private void doSomething(ActionEvent event) throws Exception {
        primaryTextArea.appendText("Hi ho!");
    }

}
Run Code Online (Sandbox Code Playgroud)

请注意,此解决方案不是最佳方法,但它很简单,可以作为一个开始.当然建议使用绑定.我会尝试创建一个包含数据的类,其他控制器绑定在该类上.但是,如果你现在采取简单的方法,它就足够了.