I've created an FXML file that allows users to see if a patient has a surgery listed in a TableView and also has the ability to add in a new surgery. To add in a new surgery the user right clicks on the TableView and a context menu appears with the menu item 'Add Surgery'. A new window appears with text fields to add in the new surgery. These are two separate FXML files with each their own controller files.
Ideal outcome - When a user adds in a new surgery, I want the TableView to refresh and add in the new data.
Within the PatientModule Controller I have the following:
@FXML
public TableView<ISurgeryModel> surgeryTableView;
ObservableList<ISurgeryModel> initialPTSurgData(){
ISurgeryModel ptSur1 = new ISurgeryModel("10/20/2023", "Other", "L", "surgeon", "facility", "comments");
return FXCollections.observableArrayList(ptSur1);
}
@Override
public void initialize(URL PatientModule, ResourceBundle resourceBundle) {
surgeryDate.setCellValueFactory((new PropertyValueFactory<ISurgeryModel, String>("surgeryDate")));
surgeryProcedure.setCellValueFactory((new PropertyValueFactory<ISurgeryModel, String>("surgeryProcedure")));
surgerySide.setCellValueFactory((new PropertyValueFactory<ISurgeryModel, String>("surgerySide")));
surgeryTableView.setItems(initialPTSurgData());
ContextMenu surgContext = new ContextMenu();
MenuItem addSurgery = new MenuItem("Add Surgery");
MenuItem viewSurgDetails = new MenuItem("View Surgery Details");
MenuItem deleteSurg = new MenuItem("Delete Surgery");
surgContext.getItems().add(addSurgery);
surgContext.getItems().add(viewSurgDetails);
surgContext.getItems().add(deleteSurg);
surgeryTableView.setContextMenu(surgContext);
addSurgery.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
try {
Parent popUp;
popUp = FXMLLoader.load(Objects.requireNonNull(GaitApplication.class.getResource("Wizards/AddSurgery.fxml")));
Stage stage1 = new Stage();
stage1.setTitle("Add Surgery: ");
stage1.setScene(new Scene(popUp, 600, 480));
stage1.show();
} catch (IOException e) {
throw new RuntimeException(e);
}
}
});
}
The AddSurgeryController has the following:
@FXML
private PatientModuleController patientModuleController;
@FXML
public void onSaveSurgery(ActionEvent event){
ISurgeryModel newData = new ISurgeryModel(date.getText(), procedure.getText(), side.getText(), surgeon.getText(), facility.getText(), comments.getText());
patientModuleController.surgeryTableView.getItems().add(newData);
this.addSurgery.getScene().getWindow().hide();
}
Currently when hitting the save button I am given the following error:
Cannot read field "surgeryTableView" because "this.patientModuleController" is null
Do I need to create a constructor for patientModuleController in the AddSurgeryController?
Here is an example performing create, update, and delete operations on a table of data utilizing separate dialog windows and FXML.
It uses some of the concepts that were discussed in the comments.
A model is created that contains an observable list with extractors.
The passing parameters option is used to pass data between the calling window and the dialog. It could have used the model for this (e.g. adding an observable currentFriend object property to the model to represent the friend currently being edited and passing the entire model to the new dialog controllers), but that wasn't necessary here.
Add functionality
This code demonstrates adding a new row to a table using data created in a new dialog window.
Example Code
module-info.java
FriendApplication.java
Friend.java
Model.java
FriendsController.java
FriendController.java
friends.fxml
friend.fxml
pom.xml
Notes on the usage of the Model class design used in this example
With this example, the Model class with the observable list isn't strictly required. You could just rely on the default list that is provided by the TableView, or one that you create and provide directly in the controller backing the TableView. However, I provided the model code so you could see how such a setup would work and the model can be used for other tasks.
Examples of tasks the observable model could be used for are:
The observable model can be extended to add additional application data and fields in the form of further observable lists and properties, but that wasn't necessary for this simple application. A larger application can have a larger observable model.
If using a dependency injection framework, such as Spring, the model can be represented as an injectable bean. Then the injection framework can inject into any component known by the injection framework (e.g. into FXML controllers via a configured FXML controller factory).
Other design notes
The example could have made use of the built-in JavaFX Dialog classes, but instead uses Stages created manually for the dialogs.