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

时间:2017-09-07 12:32:08

标签: java javafx scenebuilder

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

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

我有一个“Knopf”FXML,其中包含一个带有控制器“KnopfController”的按钮 我有一个“Feld”FXML,其中包含一个Textfield,它的控制器是“FeldController”。

“Knopf.FXML”和“Feld.FXML”都包含在Anchor Pane中。

我的代码如下:

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
}

现在我的问题是:

如何在我的按钮(如果已按下)和我的TextField(按下按钮时应该说“Hello”)之间进行交互?

按钮(Knopf.FXML中的fx:id =“Knopf”)和Feld.FXML中的TextField(fx:id =“Feld”)都可以用于我。

我如何存档?

我知道我只能在Controller中使用它们,但我想练习控制器和FXML文件之间的交互。

1 个答案:

答案 0 :(得分:0)

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

所以你会做这样的事情:

public class FeldController {

    @FXML
    private TextField textField ;

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

KnopfController需要引用"主控制器",所以它需要

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类,这在某种程度上违背了将其分解为首先是一个单独的FXML控制器对。更好的方法是在控制器之间共享数据模型,并更新/观察模型。

E.g:

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());
    // ...
}

当然,这两个控制器都需要引用相同的模型实例才能使其工作,因此您需要注入"注入"这进入控制器。您只需创建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中发布了一个这样做的例子。请注意,这只是概念验证:要像这样执行DI,您应该使用它的框架 - afterburner.fx提供一个简单但灵活的JavaFX DI框架(或者您可以使用其他标准的框架,如Spring或Guice)。