JavaFX - Objects stuck in the memory - java

I have a huge application built using JavaFX,, as there are a lot of stages to show i created a class to load views [more like utils class] called FXMLManager(i think the problem is there),, To show a single stage i should create an instance of FXMLManager,, after the stage is closed FXMLManager instances remains in the memory,,, i tried setting the object to null after the stage is closed with no luck..
FXMLManager.java:
public class FXMLManager<T extends AbstractController> {
/**
*
*/
private static ClassLoader cachingClassLoader = new FXMLlightweightLoader(FXMLLoader.getDefaultClassLoader());
private final Class<T> clazzType;
#Getter private T controller;
private FXMLLoader fxmlLoader;
#Getter private Parent root;
public FXMLManager(Class<T> clazz) {
this.clazzType = clazz;
Annotation annotation = this.clazzType.getAnnotation(FXMLController.class);
if (annotation == null)
throw new NullPointerException(
"controller type provided is not annotated with FXMLController : " + clazzType);
FXMLController fxmlController = (FXMLController) annotation;
this.fxmlLoader = constructFXMLLoader();
this.fxmlLoader.setLocation(getURL(fxmlController.value()));
try {
AbstractController abstractController = (AbstractController) clazzType.newInstance();
this.fxmlLoader.setController(abstractController);
this.root = (Parent) this.fxmlLoader.load();
} catch (Exception e) {
e.printStackTrace();
}
this.controller = this.fxmlLoader.getController();
}
private FXMLLoader constructFXMLLoader() {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setClassLoader(cachingClassLoader);
fxmlLoader.setResources(I18NSupport.getBundle());
return fxmlLoader;
}
public T getController(Class<T> controllerType) {
T controller = controllerType.cast(this.fxmlLoader.getController());
return controller;
}
public static URL getURL(String url) {
return FXMLManager.class.getResource(url);
}
private Stage stage;
public Stage getStage(String title) {
if (stage == null) {
Scene scene = new Scene(this.root);
stage = new Stage();
stage.initModality(Modality.APPLICATION_MODAL);
stage.setResizable(false);
stage.setScene(scene);
stage.getIcons().add(ImageLoader.loadImage("icon"));
}
stage.setTitle(title);
return stage;
}
}
i am using FXMLManager as follows:
public static void openRandomForm() {
FXMLManager<Controller> fxmlManager = new FXMLManager<>(Controller.class);
//fxmlManager.getController(); do stuff with the controller
Stage stage = fxmlManager.getStage("title");
stage.showAndWait();
fxmlManager = null;
}
Am i doing something wrong? as far as i know FXMLManager should be cleared,, no?
Screen shots of heap dump after showing couple of stages then performing GC:

Related

how to configure javafx with springboot with more than 1 window?

I have problem.
This is my main:
#SpringBootApplication
public class MyAppSpringApplication extends Application {
public static ConfigurableApplicationContext springContext;
private FXMLLoader fxmlLoader;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
fxmlLoader.setLocation(getClass().getResource("/sample.fxml"));
Parent root = fxmlLoader.load();
stage.setTitle("Sample app");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void stop() throws Exception {
springContext.stop();
}
#Override
public void init() throws Exception {
springContext = SpringApplication.run(MyAppSpringApplication.class);
fxmlLoader = new FXMLLoader();
fxmlLoader.setControllerFactory(springContext::getBean);
}
}
And my first window (sample.fxml) with samplecontroller and sampleservice works ok. But i create another dish-builder.fxml with their contoller and service, but when i try to use my service there, it doesnt work because of null in dishbuilderservice (albo doesnt work sampleservice in that new controller). I heard that i shound also use that:
public static ConfigurableApplicationContext springContext;
but i have no idea how should i use it. Sorry for my weak knowledge and english.
#Controller
public class DishBuilderController implements Initializable {
#Autowired
DishBuilderService dishBuilderService;
#Autowired
SampleService sampleService;
private void somefun(){
sampleService.somefunInService(); //here sampleService and
every other service has null.
}
Here is the moment when i open new dishBuilder window (its in SampleController):
#FXML
void addNoweOknoClicked(ActionEvent event) {
try {
Stage stage = (Stage)anchorPane.getScene().getWindow();
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setLocation(getClass().getResource("/dish-builder.fxml"));
AnchorPane root = fxmlLoader.load();
stage.setTitle("Sample app");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}catch (IOException e){
e.printStackTrace();
}
}
When you load dish-builder.fxml you are not setting the controller factory on the FXMLLoader. This means the FXMLLoader is simply creating the controller by calling its no-arg constructor. Since the controller is not a spring-managed bean, spring cannot inject any components into it.
You need to set the controller factory, as you do when you load sample.fxml, so that the FXMLLoader will ask Spring to retrieve the controller from the application context.
A couple of points that are not strictly relevant to your question:
There is no need to expose the ApplicationContext as a public static field. You can inject it into any spring-managed beans that need access to it
It is not recommended to re-use FXMLLoaders. Therefore there's no point in making the FXMLLoader an instance variable.
The #Controller annotation is intended for web controllers in a Spring MVC application. These are quite different to controllers in the JavaFX sense. You should use a generic #Component annotation for JavaFX controllers.
In the event that you were to reload an FXML file, you would need a new controller instance. This means that if the controller is managed by Spring, it needs to have PROTOTYPE scope, instead of the default SINGLETON scope.
So you need:
#SpringBootApplication
public class MyAppSpringApplication extends Application {
private ConfigurableApplicationContext springContext;
public static void main(String[] args) {
Application.launch(args);
}
#Override
public void start(Stage stage) throws Exception {
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setControllerFactory(springContext::getBean);
fxmlLoader.setLocation(getClass().getResource("/sample.fxml"));
Parent root = fxmlLoader.load();
stage.setTitle("Sample app");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}
#Override
public void stop() throws Exception {
springContext.stop();
}
#Override
public void init() throws Exception {
springContext = SpringApplication.run(MyAppSpringApplication.class);
}
}
Then your SampleController should look like
#Component
#Scope("prototype")
public class SampleController {
#Autowired
private ConfigurableApplicationContext springContext ;
#FXML
void addNoweOknoClicked(ActionEvent event) {
try {
Stage stage = (Stage)anchorPane.getScene().getWindow();
FXMLLoader fxmlLoader = new FXMLLoader();
fxmlLoader.setControllerFactory(springContext::getBean);
fxmlLoader.setLocation(getClass().getResource("/dish-builder.fxml"));
AnchorPane root = fxmlLoader.load();
stage.setTitle("Sample app");
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
}catch (IOException e){
e.printStackTrace();
}
}
}
and similarly
#Component
#Scope("prototype")
public class DishBuilderController implements Initializable {
#Autowired
DishBuilderService dishBuilderService;
#Autowired
SampleService sampleService;
private void somefun(){
// this should now work, since the controller is managed by Spring:
sampleService.somefunInService();
}
}

Creating a static class to open a new window in Java FXML

I am working on a project where there's a lot of windows being opened and closed and would like to create a static class which only takes in a few parameters and then does the rest.
The problem is that "controller" will need to be different types of declaration, depending on what controller is needed. For instance; FXMLControllerAdd or FXMLControllerHome.
I tried to pass the type to the method with a parameter. That did not work, neither did using var as declaration (it's coded in Java11) because then i got a "cannot find symbol"-error for initData() on the next line.
public static void nySide(Class c, String controllerPath, Dataset dataset, String tittel, Window window) {
try {
FXMLLoader loader = new FXMLLoader(c.getResource(controllerPath));
Parent root = (Parent) loader.load();
//THIS IS WHERE TO PROBLEM IS
FXMLControllerAdd controller = loader.getController();
controller.initData(dataset);
//This line gets the Stage information
Stage st = new Stage();
st.setTitle(tittel);
st.setScene(new Scene(root));
st.show();
Stage stage = (Stage) window;
stage.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Also; does it exists another way which requires less parameters?
I figured it out thanks to Slaw. Making an interface E.g (FXMLInitData) and implementing that in every FXMLController.java and declaring controller as that interface did the trick.
Interface:
public interface FXMLInitData {
public void initData(Dataset dataset);
}
Method:
public static void nySide(Class c, String controllerPath, Dataset dataset, String tittel, Window window){
try {
FXMLLoader loader = new FXMLLoader(c.getResource(controllerPath));
Parent root = (Parent) loader.load();
FXMLInitData controller = loader.getController();
controller.initData(dataset);
//This line gets the Stage information
Stage st = new Stage();
st.setTitle(tittel);
st.setScene(new Scene(root));
st.show();
Stage stage = (Stage) window;
stage.close();
} catch (Exception e) {
e.printStackTrace();
}
}
Class:
public class FXMLControllerHome implements Initializable, FXMLInitData{
#Override
public void initData(Dataset dataset){
}
}
Try letting every controller extend or implement a parent Controller-class. Make the parent Controller a parameter, and pass the child-controller as a parameter when calling the method instead of String controllerPath.

#FXML Annotation not working correctly

I'm currently working on a 'small' project with JavaFX. I used the SceneBuilder to create the first sketch of my GUI. it still needs some adjustment and styling but I wanted to see if it's working so far.
I have 2 hyperlinks on the GUI, if the user clicks one of them the default system-browser should open with a specific URL.
So far I got this:
Main.java:
public class Main extends Application {
#Override
public void start(Stage primaryStage) throws MalformedURLException, IOException {
DataBean dataBean= new DataBean(primaryStage);
Controller controller = new Controller(dataBean);
controller.show();
}
public static void main(String[] args) {
launch(args);
}
}
DataBean.java:
public class DataBean {
private Stage primaryStage;
public DataBean(Stage stage) {
primaryStage = stage;
}
public Stage getPrimaryStage() {
return primaryStage;
}
}
TestautomatView.java:
public class TestautomatView implements Initializable {
#FXML
private ComboBox<String> environmentCombo;
#FXML
private Hyperlink crhl;
#FXML
private Hyperlink help;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
private Scene scene;
private BorderPane root;
public TestautomatView() throws MalformedURLException, IOException {
root = FXMLLoader.load(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));
scene = new Scene(root);
}
public void show(Stage stage) {
stage.setTitle("CrossReport Testautomat");
stage.setScene(scene);
stage.show();
}
public ComboBox<String> getEnvironmentCombo() {
return environmentCombo;
}
public Hyperlink getCrhl() {
return crhl;
}
public Hyperlink getHelp() {
return help;
}
public Scene getScene() {
return scene;
}
}
In my controller I want to set the ActionHandler to the hyperlinks but it's not working because the getters in my view return null.
public class Controller {
private DataBean dataBean;
private TestautomatView view;
public Controller(DataBean databean) throws MalformedURLException, IOException {
this.dataBean = databean;
this.view = new TestautomatView();
setActionHandlers();
}
public void show() throws MalformedURLException, IOException {
view.show(dataBean.getPrimaryStage());
}
private void setActionHandlers() {
// setHyperlink(view.getCrhl(), "www.example.com");
// setHyperlink(view.getHelp(), "www.example2.com");
}
private void setHyperlink(Hyperlink hl, String uri) {
hl.setOnAction(new EventHandler<ActionEvent>() {
#Override
public void handle(ActionEvent event) {
//TODO - Open Default Browser
}
});
}
}
When I start my application, I can see the GUI but when I want to add the ActionHandlers I get a NullPointerException.
In the ´Sample.fxml´ file the hyperlinks are children of a HBox
<Hyperlink fx:id="crhl" text="Report" />
<Hyperlink fx:id="help" text="Help" />
But it's not just the hyperlinks even the ComboBox is null when I inspect my app in the debugger.
Where is my mistake?
The problem is that you are creating your controller manually by using new TestautomatView(). It must be created by FXMLLoader for annotations to work. You must also set fx:controller attribute in Sample.fxml to your controller (TestautomatView) fully qualified class name.
Example code:
FXMLLoader fl = new FXMLLoader(new URL(TestautomatView.class.getResource("Sample.fxml").toExternalForm()));
root = fl.load();
TestautomatView controller = fl.getController();
PS: You should rename your TestautomatView to TestautomatController. FXML file is your "view".
As pointed out in another answer, the issue is that you create an instance of TestautomatView "by hand". The default behavior of the FXMLLoader is to create an instance of the controller class specified in the FXML file, and use that instance as the controller. Consequently, you have two instances of TestautomatView: the one you created (and have a reference to), and the one that was created by the FXMLLoader. It is the second one that has the #FXML-annotated fields initialized.
You can change this default behavior by creating an FXMLLoader instance, and setting the controller on it directly. E.g. consider doing:
public class TestautomatView implements Initializable {
#FXML
private ComboBox<String> environmentCombo;
#FXML
private Hyperlink crhl;
#FXML
private Hyperlink help;
#Override
public void initialize(URL location, ResourceBundle resources) {
}
private Scene scene;
private BorderPane root;
public TestautomatView() throws MalformedURLException, IOException {
FXMLLoader loader = new FXMLLoader(TestautomatView.class.getResource("Sample.fxml"));
loader.setController(this);
root = loader.load();
scene = new Scene(root);
}
// etc...
}
Since you are directly setting the controller, you need to remove the fx:controller attribute from the Sample.fxml file for this to work.
You may also be interested in this pattern, which is quite similar (though not exactly the same) as what you are trying to do here.

JavaFX & Spring Boot - NPE

I'm still fighting with my issue. I want to use Spring Framework in order to incject dependencies and I have to use Spring boot to integrate both.
Unfortunately, in first view autowiring is run correctly, but if I go next Stage, I got still only Null Pointer Exception.
Thats main class:
#SpringBootApplication(scanBasePackages = "boxingchallenge")
public class BoxingChallengeApplication extends Application {
public ConfigurableApplicationContext springContext;
private Parent root;
public static Stage stage;
#Override
public void init() throws Exception {
springContext = SpringApplication.run(BoxingChallengeApplication.class);
springContext.getAutowireCapableBeanFactory().autowireBean(this);
FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/FXML/start.fxml"));
fxmlLoader.setControllerFactory(springContext::getBean);
root = fxmlLoader.load();
}
#Override
public void start(Stage primaryStage) throws Exception {
stage = primaryStage;
primaryStage.setTitle("Boxing challenge");
Scene scene = new Scene(root);
primaryStage.setScene(scene);
primaryStage.show();
}
#Override
public void stop() {
springContext.stop();
}
public static void main(String[] args) {
launch(BoxingChallengeApplication.class, args);
}
}
Here in first controller class autowiring run cool:
#Component
public class Start {
#FXML
public Button loadGame;
#FXML
public Button create;
#Autowired
private Boxer boxer;
public void load(ActionEvent event) {
System.out.println(boxer.getName());
}
//next stage
public void createNew(ActionEvent event) throws IOException {
Parent root = FXMLLoader.load(getClass().getResource("/FXML/creator.fxml"));
BoxingChallengeApplication.stage.setScene(new Scene(root));
}
}
Here in second stage, autowiring not working:
#Component
public class Creator {
#FXML
public Button ready;
public TextField nation;
public TextField name;
public Boxer boxer;
/*#Autowired
private ApplicationContext context;*/
#Autowired
public void setBoxer(Boxer boxer) {
this.boxer = boxer;
}
public void createdAndPlay(ActionEvent event) {
if (boxer == null)
System.out.println("boxer is null");
else
System.out.println("Injected correctly");
}
}
Thanks, i hope it's going to finished...
#Jewelsea's comment is correct: you must set the controller factory when you load creator.fxml. If you don't do this, the FXMLLoader will create the controller simply by calling its no-arg constructor, so Spring will know nothing about it and will have no opportunity to inject any dependencies.
To do this, all you need is access to the ApplicationContext in Start, and you can inject "well-known objects", of which the ApplicationContext is an example, into your Spring-managed beans:
#Component
public class Start {
#FXML
public Button loadGame;
#FXML
public Button create;
#Autowired
private Boxer boxer;
#Autowired
private ApplicationContext context ;
public void load(ActionEvent event) {
System.out.println(boxer.getName());
}
//next stage
public void createNew(ActionEvent event) throws IOException {
FXMLLoader loader = new FXMLLoader(getClass().getResource("/FXML/creator.fxml"));
load.setControllerFactory(context::getBean);
Parent root = loader.load();
BoxingChallengeApplication.stage.setScene(new Scene(root));
}
}
As an aside, you almost certainly want a new instance of any controller when you load an FXML file, so you should probably make any controllers prototype scope.

Send a object to other screen in javafx

I'm new in the javafx and until now is going good. But I don't find any form to send a object from a screen to another. I have some dificult to understand funciont od annotations #FXML and the method initialize from Initializable interface
Class that calls another
public class FluxoCaixaController extends ParametrosTelas implements iTelaPrincipalFX {
/*Atributos locais*/
private ObservableList<String> opcoes = FXCollections.observableArrayList("Receita", "Despesa");
private Object parent;
private AberturaDeTelasFX formaAbertura;
private ToggleGroup modalGroup = new ToggleGroup();
private Categoria categoria;
private CategoriaTreeViewController root = new CategoriaTreeViewController();
#Override
public void showScreen() {
formaAbertura = new AberturaDialogFX();
formaAbertura.loadFXML(bundle, icone, bundle.getString("screnn.fluxo.title"), new AnchorPane(), "FluxoCaixa.fxml");
}
#Override // This method is called by the FXMLLoader when initialization is complete
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
tipoField.getItems().setAll(opcoes);
root.setParentController(getInstance());
//idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
//descricaoColumn.setCellValueFactory(new PropertyValueFactory<>("descricao"));
//atualizaTabela();
}
#FXML
private void btnAddCetegoria() {
root.showScreen();
categoriaSubcategoriaField.setText(categoria.getDescricao());
}
private Object getInstance(){
return this;
}
Class called
public class CategoriaTreeViewController extends ParametrosTelas implements iTelaNormalFX {
private AberturaDeTelasFX formaAbertura;
private Object parent;
private CategoriaService categoriaService = new CategoriaService();
#FXML
private TreeView<Categoria> treeView;
private Categoria EmptyCategoria;
private TreeItem<Categoria> rootItem;
private EventHandler<MouseEvent> mouseEventHandle;
#Override
public void showScreen() {
formaAbertura = new AberturaDialogFX();
formaAbertura.loadFXML(bundle, icone, bundle.getString("screnn.subcategory.title"), new AnchorPane(), "CategoriaTreeView.fxml");
}
#Override // This method is called by the FXMLLoader when initialization is complete
public void initialize(URL fxmlFileLocation, ResourceBundle resources) {
initialiazeTree();
mouseEventHandle = (MouseEvent event) -> {
handleMouseClicked(event);
};
treeView.addEventHandler(MouseEvent.MOUSE_CLICKED, mouseEventHandle);
treeView.setRoot(rootItem);
}
private void initialiazeTree() {
EmptyCategoria = new Categoria();
EmptyCategoria.setDescricao("Categorias");
rootItem = new TreeItem<>(EmptyCategoria);
// private TreeItem<SubCategoria> itens = new TreeItem<>();
for (Categoria g : categoriaService.listaCategorias()) {
List<Categoria> subLst = categoriaService.listaSubCategoriasByCategoria(g.getId());
TreeItem<Categoria> itens = new TreeItem<>(g);
//ObservableList<Categoria> subData = FXCollections.observableArrayList(subLst);
for (Categoria s : subLst) {
s.setCategoria(g);
TreeItem<Categoria> subItem = new TreeItem<>(s);
//subItem.addEventHandler(MouseEvent, new EventHandler<MouseEvent>() {
itens.getChildren().add(subItem);
}
//itens.getChildren().add(itens);
rootItem.getChildren().add(itens);
}
}
private void handleMouseClicked(MouseEvent event) {
if (treeView.getSelectionModel().getSelectedItem() != null) {
Categoria name = (Categoria) ((TreeItem) treeView.getSelectionModel().getSelectedItem()).getValue();
FluxoCaixaController fluxo = (FluxoCaixaController) getParentController();
fluxo.setCategoria(name);
System.out.println("Node click: " + name.getDescricao());
formaAbertura.getStage().hide();
}
/*Node node = event.getPickResult().getIntersectedNode();
// Accept clicks only on node cells, and not on empty spaces of the TreeView
if (node instanceof Text || (node instanceof TreeCell && ((TreeCell) node).getText() != null)) {
String name = (String) ((TreeItem)treeView.getSelectionModel().getSelectedItem()).getValue();
System.out.println("Node click: " + name);
}*/
}
}
Must of the interfaces just point to on or two methods. The AberturaDeTelasFX interface has a Implementation that says how the screen should open.
AberturaNormalFX
public class AberturaNormalFX implements AberturaDeTelasFX {
private Stage stage;
#Override
public void loadFXML(ResourceBundle bundle, Image icon, String title, Node node, String fxmlPath) {
try {
// Carrega o root layout do arquivo fxml.
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass()
.getResource(fxmlPath));
loader.setResources(bundle);
if (node instanceof BorderPane) {
BorderPane rootLayout = (BorderPane) loader.load();
showLayout(icon, title, rootLayout);
} else if (node instanceof AnchorPane) {
AnchorPane rootLayout = (AnchorPane) loader.load();
showLayout(icon, title, rootLayout);
}
} catch (IOException e) {
e.printStackTrace();
}
}
private void showLayout(Image icone, String title, Parent node) {
stage = new Stage();
Scene scene = new Scene(node);
stage.setTitle(title);
stage.getIcons().add(icone);
stage.setScene(scene);
stage.show();
}
#Override
public void loadFXML(String title, Node node, String fxmlPath) {
throw new UnsupportedOperationException("Not supported yet."); //To chan
ge body of generated methods, choose Tools | Templates.
}
/**
* #return the stage
*/
#Override
public Stage getStage() {
return stage;
}
}
Looking on your code I did not find a class, which extends Application.
In my project, which I built recently, I used it as a part of the Presentation layer, kind of a bridge between controllers (which represent Controller layer), where each controller manages a single screen. Consider following example:
public class MainAppFX extends Application {
// The primary window or frame of this application
private Stage primaryStage;
this 'patient' represents object from your controller:
private PatientData patient;
/**
* Default constructor
*/
public MainAppFX() {
super();
}
/**
* The application starts here
*
* #param primaryStage
* #throws Exception
*/
#Override
public void start(Stage primaryStage) throws Exception {
log.info("Program loads");
// The Stage comes from the framework so make a copy to use elsewhere
this.primaryStage = primaryStage;
// Create the Scene and put it on the Stage
loadPatientParentWindow();
// Set the window title
this.primaryStage.setTitle("Your Window title");
this.primaryStage.show();
}
/**
* Loads Patient FXML layout
* This method loads one of your screens
*/
public void loadPatientParentWindow() {
try {
// Instantiate the FXMLLoader
FXMLLoader loader = new FXMLLoader();
// Set the location of the fxml file in the FXMLLoader
loader.setLocation(MainAppFX.class.getResource("/fxml/PatientForm.fxml"));
// Parent is the base class for all nodes that have children in the
// scene graph such as AnchorPane and most other containers
Parent parent = (AnchorPane) loader.load();
// Load the parent into a Scene
Scene scene = new Scene(parent);
// Put the Scene on Stage
primaryStage.setScene(scene);
// Give the PatientFXMLController controller access to the main app.
PatientFXMLController controller = loader.getController();
below is the setter method of Patient controller, where it gets an access to the Main class
controller.setMainAppFX(this);
} catch (IOException | SQLException ex) { // getting resources or files could fail
log.error(null, ex);
System.exit(1);
}
}
/**
* Setter for PatientData object in the Main class
you use it in the controller class
*
* #param patient
*/
public void setPatient(PatientData patient) {
this.patient = patient;
}
/**
* Getting PatientData object from the Main class
*
* #return
*/
public PatientData getPatient() {
return patient;
}
/**
* Where it all begins
*
* #param args command line arguments
*/
public static void main(String[] args) {
launch(args);
System.exit(0);
}
}
And here is one of the controller classes, which represent one of the screens:
public class PatientFXMLController {
Reference to the main application starts here
private MainAppFX mainApp;
Next object you will be passing to the main class using setters
private PatientData patient;
// The #FXML annotation on a class variable results in the matching
// reference being injected into the variable
// label is defined in the fxml file
// Bunch of #FXML annotations with respective fields (you can get them from SceneBuilder)
#FXML
private TextField patientIdField;
#FXML
private TextField lastNameField;
// so on...
/**
* The constructor. The constructor is called before the initialize()
* method. You don't need to call it. It's being called by automatically
*/
public PatientFXMLController() {
super();
Create empty Patient object for initialize method
patient = new PatientData();
}
/**
* Initializes the controller class. This method is automatically called
* after the fxml file has been loaded. Useful if a control must be
* dynamically configured such as loading data into a table.
*/
#FXML
private void initialize() {
log.info("initialize called");
// Initializing form fields
Bindings.bindBidirectional(patientIdField.textProperty(), patient.patientIdProperty(), new NumberStringConverter());
// so on .....
}
/**
* Loads Another screen
this method below represents an action for a button, which leads to another screen, and where you passing an object from this controller to the main class. And then you can pass this object from main class to anotherScreen controller, since you will have its loadAnotherScreenWindow() method there
*
* #param event
*/
#FXML
private void loadAnotherScreen(ActionEvent event) throws SQLException {
Passing Patient object to the main class so it can be used in Another screen controller to get related inpatients
mainApp.setPatient(patient);
}
/**
* Is called by the main application to give a reference back to itself.
* This class receives the reference of the main class.
*
* #param mainApp
*/
public void setMainAppFX(MainAppFX mainApp) {
this.mainApp = mainApp;
}
/**
* Setter for PatientData object
*
* #param patient
*/
public void setPatient(PatientData patient) {
this.patient = patient;
}
}

Categories