首页 文章

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

提问于
浏览
0

我是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

    一种简单的方法是在每个控制器中定义所需的方法,并从事件处理程序中调用它们 . 在这种情况下, 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 类,这在一定程度上违背了将其分解为一个单独的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());
        // ...
    }
    

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

相关问题