Вы не устанавливаете фабрику контроллера на FXMLLoader
при загрузке reportFrame.fxml
.Следовательно, когда FXMLLoader
требуется экземпляр ReportFrameController
, он просто создает его экземпляр напрямую, а не получает его из контекста приложения Spring.Поскольку spring не управляет контроллером, в него ничего нельзя вставить.
Просто используйте тот же шаблон для загрузки reportFrame.fxml
, который вы использовали для загрузки mainFrame.fxml
.Вы можете вставить ApplicationContext
в контроллер, чтобы сделать это.Обратите внимание, что это означает, что ваш MenuFrameController
также должен управляться пружиной (поэтому используйте ту же технику, когда вы загружаете соответствующий файл FXML и т. Д.).
Кроме того, вы должны сделать все свои прототипы контроллера,так как каждый раз, когда вы загружаете один и тот же файл FXML, вам понадобится новый экземпляр контроллера.
@Controller
@Scope("prototype")
public class MenuFrameController {
@FXML
private Button generateReportButton;
@Autowired
private ApplicationContext springContext ;
@FXML
void generateReportButtonClicked(ActionEvent event) throws Exception {
try {
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/fxml/reportFrame.fxml"));
fxmlLoader.setControllerFactory(springContext::getBean);
Parent root = fxmlLoader.load();
Scene scene = new Scene(root);
Stage stage = (Stage) generateReportButton.getScene().getWindow();
stage.setTitle("Generate new report");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
System.out.println("Failed to create Generate Window.");
}
}
}
Если вы хотите, вы можете уменьшить количество повторяющегося кода, создав класс, который инкапсулирует функциональность загрузки.и вставьте его экземпляр везде, где вам это нужно:
public class SpringFXMLLoader {
@Autowired
private ApplicationContext springContext ;
public Parent load(String resourceName) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource(resourceName));
loader.setControllerFactory(springContext::getBean);
return loader.load();
}
}
Тогда ваш основной класс может выполнить
@Override
public void init() throws Exception {
springContext = SpringApplication.run(ServiceappApplication.class);
rootNode = springContext.getBean(SpringFXMLLoader.class).load("/fxml/mainFrame.fxml");
}
, а ваш MenuFrameController
упрощается (немного) до
@Controller
@Scope("prototype")
public class MenuFrameController {
@FXML
private Button generateReportButton;
@Autowired
private SpringFXMLLoader fxmlLoader ;
@FXML
void generateReportButtonClicked(ActionEvent event) throws Exception {
try {
Parent root = fxmlLoader.load("/fxml/reportFrame.fxml");
Scene scene = new Scene(root);
Stage stage = (Stage) generateReportButton.getScene().getWindow();
stage.setTitle("Generate new report");
stage.setScene(scene);
stage.show();
} catch (IOException e) {
System.out.println("Failed to create Generate Window.");
}
}
}