Javafx将参数和值从一个控制器传递到另一个控制器

Bio*_*ack 3 controller javafx

我是JavaFx的新手,因此我无法找到解决问题的解决方案

假设我有以下应用程序结构:

- views
      - first.fxml -> this has a button called btnSend and a textfield called txtEnter
      - second.fxml -> this has a textarea called txtView
- Controller 
      - FirstController  -> controller for First
      - SecondController -> controller for second
- Modal
      - AppModal -> here I have a getter and a setter method , 
                    as getText() and setText(String text)

- App
     - Main.java -> This one used FXMLLoader to load first.fxml and second.fxml together.
Run Code Online (Sandbox Code Playgroud)

在SecondController中显示文本的最佳/最佳方式是什么?从FirstController传递它.我的意思是,我输入一个文本txtEnter然后按下按钮btnSend,按下按钮后我希望显示的文本txtView正在使用另一个控制器.我已经阅读了很多关于它的内容observers pattern并且JavaFX properties可以用来解决这个问题,但遗憾的是我无法实现一个有效的解决方案.

如果专家可以帮助我,我会感到谦卑.我知道它不正确,但任何人都可以为我提供上述项目结构的工作解决方案.

提前致谢.

Jam*_*s_D 10

StringProperty在模型中使用observable :

public class AppModel {

    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);
    }
}
Run Code Online (Sandbox Code Playgroud)

使您的控制器可以访问模型:

public class FirstController {

    private final AppModel model ;

    @FXML
    private TextField textEnter ;

    public FirstController(AppModel model) {
        this.model = model ;
    }

    // action event handler for button:
    @FXML
    private void sendText() { 
        model.setText(textEnter.getText());
    }
}
Run Code Online (Sandbox Code Playgroud)

和

public class SecondController {

    private final AppModel model ;

    @FXML
    private TextArea txtView ;

    public SecondController(AppModel model) {
        this.model = model ;
    }

    public void initialize() {
        // update text area if text in model changes:
        model.textProperty().addListener((obs, oldText, newText) -> 
            txtView.setText(newText));
    }
}
Run Code Online (Sandbox Code Playgroud)

现在稍微棘手的部分是控制器没有no-arg构造函数,这意味着FXMLLoader创建它们的默认机制将不起作用.最简单的方法是手动设置它们.从FXML文件中删除这两个<fx:controller>属性,然后在Main类中删除

AppModel model = new AppModel();

FXMLLoader firstLoader = new FXMLLoader(getClass().getResource("first.fxml"));
firstLoader.setController(new FirstController(model));
Parent firstUI = firstLoader.load();

FXMLLoader secondLoader = new FXMLLoader(getClass().getResource("second.fxml"));
secondLoader.setController(new SecondController(model));
Parent secondUI = secondLoader.load();
Run Code Online (Sandbox Code Playgroud)

如果您希望将<fx:controller>属性保留在FXML文件中,则可以使用controllerFactory替代,它实质上指示FXMLLoader如何创建控制器:

AppModel model = new AppModel();

Callback<Class<?>, Object> controllerFactory = type -> {
    if (type == FirstController.class) {
        return new FirstController(model);
    } else if (type == SecondController.class) {
        return new SecondController(model);
    } else {
        try {
            return type.newInstance() ; // default behavior - invoke no-arg construtor
        } catch (Exception exc) {
            System.err.println("Could not create controller for "+type.getName());
            throw new RuntimeException(exc);
        }
    }
};

FXMLLoader firstLoader = new FXMLLoader(getClass().getResource("first.fxml"));
firstLoader.setControllerFactory(controllerFactory);
Parent firstUI = firstLoader.load();

FXMLLoader secondLoader = new FXMLLoader(getClass().getResource("second.fxml"));
secondLoader.setControllerFactory(controllerFactory);
Parent secondUI = secondLoader.load();
Run Code Online (Sandbox Code Playgroud)

通过使用(更多)反射,您可以使控制器工厂更加灵活; 基本上你可以实现逻辑"如果控制器类型有一个构造函数接受AppModel,调用该构造函数,否则调用no-arg构造函数".

如果您正在创建需要执行大量此操作的大型应用程序,那么您可以考虑使用afterburner.fx,这是一个基本上允许您使用注释将模型注入控制器的框架.