I have a gui built with javafx the controllers are loaded from fxml and created as Beans with spring so I can access my model. But that is predefined in fxml and loaded at start. Now I would like to load components, defined in fxml at runtime, but I could not yet find a working example, and no matter how I try it doesn't work.
So my question:
- How can I create a custom Dialog (or any custom component) in runtime , that is loaded from .fxml and is aware of (Spring application) context?
Edit
So it loads but some fields are not initialized. This is my custom DialogPane,
@Controller
@Scope("prototype")
public class NewProgramDialogPane extends DialogPane implements Initializable {
public static final ButtonType buttonTypeOk = new ButtonType("Create", ButtonBar.ButtonData.OK_DONE);
public static final ButtonType buttonTypeCancel = new ButtonType("Cancel", ButtonBar.ButtonData.CANCEL_CLOSE);
public TextField nameField;
public TextField data1Field;
public TextField data2Field;
public RegexValidator requiredField1;
public RequiredField requiredField2;
public RequiredField requiredField3;
public ErrorLabel duplicateProjectErrorLabel;
private SimpleBooleanProperty match = new SimpleBooleanProperty(false);
@Autowired
MainService mainService;
public NewProgramDialogPane() {
URL url = getClass().getClassLoader().getResource("com/akos/fxml/NewProgramDialog.fxml");
FXMLLoader loader = new FXMLLoader();
loader.setLocation(url);
loader.setRoot(this);
try {
loader.load();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public void initialize(URL location, ResourceBundle resources) {
this.lookupButton(buttonTypeOk).addEventHandler(ActionEvent.ACTION, event -> {
if (!validate()) {
event.consume();
}
});
duplicateProjectErrorLabel.visibleProperty().bind(match);
}
public boolean validate() {
requiredField1.eval();
requiredField2.eval();
requiredField3.eval();
match.set(mainService.getPrograms().stream().anyMatch(
program -> program != null && program.getName().equals(nameField.getText())));
return !match.get() &&
!requiredField1.getHasErrors() &&
!requiredField2.getHasErrors() &&
!requiredField3.getHasErrors();
}
}
And when I try to read the nameField, it is null.
public class NewProgramDialog extends Dialog<Program> {
public NewProgramDialog() {
this.setDialogPane(new NewProgramDialogPane());
this.setTitle("New program");
this.initModality(Modality.APPLICATION_MODAL);
this.initStyle(StageStyle.DECORATED);
this.setResultConverter(param -> {
if (param == NewProgramDialogPane.buttonTypeOk) {
int x = 0;
return new Program(((NewProgramDialogPane) getDialogPane()).nameField.getText());
}
return null;
});
}
}
loader.setController(this);NewProgramDialogPaneexplicitly, instead of letting Spring instantiate it for you. Make theNewProgramDialogPanea spring-managed bean, and inject it into theNewProgramDialog. Combining two different frameworks like this is tricky; you may want to just spend some time understanding Spring on its own first.