如何影响来自其他控制器的 fx:id 个元素

How to influence fx:id Elements from other Controllers

我是 Java FX 的新手,对控制器、FXML 文件及其交互有一些基本的理解问题。

我正在使用 Scenebuilder 并尝试了一些简单的方法。 我有一个只有 AnchorPane 的 FXML 文件,它与控制器链接 class。与其他 FXML 控制器一起玩应该是我的主要 class。

我有一个 "Knopf" FXML,它只包含一个带有控制器的按钮 "KnopfController" 我有一个 "Feld" FXML,其中包含一个文本字段及其控制器 "FeldController"。

"Knopf.FXML" 和 "Feld.FXML" 都包含在锚定窗格中。

我的代码如下所示:

package sample;

import javafx.fxml.FXML;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.AnchorPane;

public class Controller {

@FXML
private AnchorPane Main;

@FXML
private FeldController feldController;

@FXML
private KnopfController knopfController;

public void textChange(MouseEvent event){
    //Hier Comes the Code
}

现在我的问题是:

我如何在我的 Button(如果它被按下)和我的 TextField(按下按钮时它应该说 "Hello"?

Button(fx:id="Knopf" in the Knopf.FXML)和TextField(fx:id="Feld" in the Feld.FXML)应该可用对我来说。

我该如何存档?

我知道我可以在控制器中同时使用两者,但我想练习控制器和 FXML 文件之间的交互。

一个简单的方法就是在每个控制器中定义您需要的方法并从事件处理程序中调用它们。在这种情况下,您的 KnopfController 将需要调用主控制器中的 textChange() 方法(因此它需要对 Controller 的引用),然后 textChange() 将调用一个FeldController 中的方法。

所以你会做这样的事情:

public class FeldController {

    @FXML
    private TextField textField ;

    public void updateText(String text) {
        textField.setText(text);
    }
}

KnopfController 需要引用 "main controller",因此需要

public class KnopfController {

    private Controller mainController ;

    public void setMainController(Controller mainController) {
        this.mainController = mainController ;
    }

    // button handler:
    @FXML
    private void handleButtonClick(ActionEvent event) {
        mainController.textChange("Hello");
    }
}

现在您的主控制器将它们连接在一起:

public class Controller {

    @FXML
    private AnchorPane Main;

    @FXML
    private FeldController feldController;

    @FXML
    private KnopfController knopfController;

    public void initialize() {
        knopfController.setMainController(this);
    }

    public void textChange(String newText){
        feldController.updateText(newText);
    }
}

虽然这可行,但这里的设计问题是您已将控制器紧密耦合(例如,您的 KnopfController 取决于 Controller class,这在某种程度上不利于首先将其分解为单独的 FXML 控制器对的想法)。更好的方法是在控制器之间共享一个数据模型,update/observe 模型。

例如:

public class Model {

    private final StringProperty text = new SimpleStringProperty() ;

    public StringProperty textProperty() {
        return text ;
    }

    public final String getText() {
        return textProperty().get();
    }

    public final void setText(String text) {
        textProperty().set(text);
    }
}

现在的基本思路是做

public class KnopfController {

    private Model model ;

    @FXML
    private void handleButton() {
        model.setText("Hello");
    }
}

public class FeldController {

    @FXML
    private TextField textField ;

    private Model model ;

    // ...
        textField.textProperty().bindBidirectional(model.textProperty());
    // ...
}

当然,这两个控制器都需要引用相同的模型实例才能正常工作,因此您需要 "inject" 将其添加到控制器中。您可以通过创建 setModel() 方法并调用它们来做到这一点:

public class KnopfController {

    private Model model ;

    public void setModel(Model model) {
        this.model = model ;
    }

    @FXML
    private void handleButton() {
        model.setText("Hello");
    }
}

对于FeldController,您可以在设置模型时进行绑定:

 public class FeldController {

    @FXML
    private TextField textField ;

    private Model model ;

    public void setModel(Model model) {
        this.model = model ;
        textField.textProperty().bindBidirectional(model.textProperty());
    }
}

然后你的主控制器就减少到:

public class Controller {

    private Model model ;

    @FXML
    private FeldController feldController;

    @FXML
    private KnopfController knopfController;

    public void initialize() {
        model = new Model();
        knopfController.setModel(model);
        feldController.setModel(model);
    }
}

您可以更进一步,使用控制器工厂为您提供模型给控制器。我在 github repo. Note this is only proof-of-concept: to do DI like this you should probably use a framework for it - afterburner.fx 中发布了一个这样做的示例,它提供了一个简单但灵活的 JavaFX DI 框架(或者您可以使用其他标准框架,例如 Spring 或 Guice)。