通过 Java FX Controller 将数据传递到其他视图

Passing data through Java FX Controller to other View

我想这是一个简单的问题,但这是漫长的一天工作,我现在无法找到正确的出路。

我有 3 个 FXML 文件。

我和往常一样从 Main.java 开始

@Override
public void start(Stage primaryStage) {
    try {
        AnchorPane root = (AnchorPane)FXMLLoader.load(getClass().getResource("Start.fxml"));
        Scene scene = new Scene(root);
        scene.getStylesheets().add(getClass().getResource("application.css").toExternalForm());
        primaryStage.setScene(scene);
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

MainController 里面,我有以下内容 ActionListener

@FXML
void actionListenerMenge(ActionEvent event) {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Menge.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();
        Stage stage = new Stage();
        stage.setScene(new Scene(root1));  
        stage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

所以我通过 FXMLLoader 打开 Suche.fxml。 现在我的 Suche-View 中有一个 button,它打开了另一个场景,用户应该在其中搜索特定的数据记录。

@FXML
void actionListenerSuche(ActionEvent event) {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Suche.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();
        Stage stage = new Stage();
        stage.setScene(new Scene(root1));  
        stage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

SucheController 我正在通过 FXMLLoader

再次加载 MengeController
FXMLLoader loader = new FXMLLoader(getClass().getResource("Menge.fxml"));
try {
    Parent root = loader.load();
} catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
}
MengeController controller = (MengeController)loader.getController();

我想编辑 TextField @ MengeController 中的值以更新我的 Menge.fxml 中的视图。但如果我这样做

controller.setTextFieldValue("abc")它没有更新。我知道这一定是因为我加载了 MengeController 两次,所以有两个实例。但是我不知道如何只加载一次或注入它来更新 MengeController.

中的 TextField

选项 1:观察 SucheController 中的 属性:

SucheController中定义一个属性。不要尝试返回对 MengeController 的引用,只需设置 属性:

public class SucheController {

    private final ObjectProperty<Foo> foo = new SimpleObjectProperty<>();

    public ObjectProperty<Foo> fooProperty() {
        return foo() ;
    }

    public final Foo getFoo() {
        return fooProperty().get();
    }

    public final void setFoo(Foo foo) {
        fooProperty().set(foo);
    }

    // ...

    @FXML
    private void someHandlerMethod() {

        // FXMLLoader loader = new FXMLLoader(getClass().getResource("Menge.fxml"));
        // try {
        //     Parent root = loader.load();
        // } catch (IOException e) {
        //     e.printStackTrace();
        // }
        // MengeController controller = (MengeController)loader.getController();

        setFoo(...);
    }
}

显然将 Foo 替换为表示用户在此处提供的任何数据的类型,并相应地命名 属性 和方法...

现在当您加载 Suche.fxml 时,只需获取对控制器的引用并观察 属性。然后您可以直接在 MengeController 本身中更新文本字段:

@FXML
void actionListenerSuche(ActionEvent event) {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Suche.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();

        SucheController sucheController = loader.getController();
        sucheController.fooProperty().addListener((obs, oldFoo, newFoo) -> {
            someTextField.setText(newFoo.getSomeValue());
            // ...
        });

        Stage stage = new Stage();
        stage.setScene(new Scene(root1));  
        stage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

选项 2:将对 MengeController 的引用直接传递给 SucheController

另一个我不太喜欢的选项,因为它涉及控制器之间的更多耦合,只是将对 MengeController 的引用传递给 SucheController:

public class SucheController {

    private MengeController mengeController ;

    public void setMengeController(MengeController mengeController) {
        this.mengeController = mengeController ;
    }

    // ...

    @FXML
    private void someHandlerMethod() {

        mengeController.setTextFieldValue("abc");

    }
}

然后 MengeController 中加载 Suche.fxml 的代码看起来像

@FXML
void actionListenerSuche(ActionEvent event) {
    try {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("Suche.fxml"));
        Parent root1 = (Parent) fxmlLoader.load();

        SucheController sucheController = fxmlLoader.getController();
        sucheController.setMengeController(this);

        Stage stage = new Stage();
        stage.setScene(new Scene(root1));  
        stage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}