【问题标题】:How to influence fx:id Elements from other Controllers如何影响来自其他控制器的 fx:id 元素
【发布时间】:2017-09-07 12:32:08
【问题描述】:

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

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

我有一个“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(Knopf.FXML 中的 fx:id="Knopf")和 TextField(Feld.FXML 中的 fx:id="Feld")都应该对我有用。

我该如何存档?

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

【问题讨论】:

  • 好吧,我想我现在明白了。我必须在“Feld”控制器和“Knopf”控制器类中实现方法,所以我可以在我的主控制器类中使用它。
  • 最好的方法是使用 MVC(或类似的)方法。与不同的控制器共享模型并更新/观察模型中的数据。参见例如stackoverflow.com/questions/32342864/applying-mvc-with-javafx。另一种方法是将Controller的引用传递给KnopfController,这样你就可以在按钮事件处理程序中调用textChange(),然后只需定义一个方法来更新FeldController中的文本字段并调用它来自textChange() 方法。
  • 谢谢我尝试了你的第二种方法。我得到一个 NullpointerException,我在 KnopfController 中使用 textChange() 方法。我刚刚添加了@FXML Controller 控制器;到 KnopfController。你能告诉我我必须写什么才能将它放入 FXML 文件吗?将它包含在 SceneBuilder 中并不是我想的解决方案。
  • 是的,那行不通(Knopf.fxml 中的fx:id="controller" 没有任何内容)。您必须在KnopfController 中创建一个setController(...) 方法,并从主控制器的initialize() 方法中调用knopfController.setController(this)

标签: java javafx scenebuilder


【解决方案1】:

一个简单的方法就是在每个控制器中定义你需要的方法并从事件处理程序中调用它们。在这种情况下,您的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- 的想法。首先是控制器对)。更好的方法是在控制器之间共享数据模型,并更新/观察模型。

例如:

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 )。

【讨论】:

  • 哇,伙计,非常感谢您的努力!我会试着看看它。今天阅读第一部分,在理解 MVC 以及如何使用它方面遇到了问题。(创建新模型的模型部分)这也是我第一次遇到 initialize() 方法和 setController 方法。希望我会进入它。会读进去。希望我会在完全理解后向您推荐。可惜没我想的那么简单,简单的事情就这么复杂。
猜你喜欢
  • 2011-05-29
  • 2019-01-27
  • 2015-09-27
  • 1970-01-01
  • 1970-01-01
  • 2021-06-07
相关资源
最近更新 更多