我是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.
在SecondController中显示文本的最佳/最佳方式是什么?从FirstController传递它。我的意思是,我在txtEnter
中输入了一个文本,然后按下按钮btnSend
,按下按钮后,我希望文本显示在使用另一个控制器的txtView
中。
我已经阅读了很多关于observers pattern
和JavaFX properties
可用于解决此问题的内容,但遗憾的是我无法实现有效的解决方案。
如果专家可以帮助我,我会感到谦卑。我知道它不正确,但任何人都可以为我提供上述项目结构的工作解决方案。
提前致谢。
答案 0 :(得分:10)
在模型中使用可观察的StringProperty
:
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);
}
}
让您的控制器可以访问该模型:
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());
}
}
和
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));
}
}
现在稍微棘手的部分是控制器没有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();
如果您希望将<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();
通过使用(更多)反射,您可以使控制器工厂更加灵活;基本上你可以实现逻辑“如果控制器类型有一个构造函数接受AppModel
,调用该构造函数,否则调用no-arg构造函数”。
如果您正在创建一个需要执行大量此操作的大型应用程序,那么您可以考虑使用afterburner.fx,这是一个基本上允许您使用注释将模型注入控制器的框架。