Issue
I want to make it where in the tableview if the First Dose Appointment Date of a certain row is 0000-01-01, then it will display N/A instead of 0000-01-01 for that specific row, but since i had already declared the fDoseDateColumn as <Recipient, LocalDate>, i dont know how i can assign a String type "N/A" to it, so im trying to find way to do this.
These are the codes of this scene:
@SuppressWarnings("unchecked")
public void ViewAllRecipientData(Stage stage, GridPane gridPane, ObservableList<Recipient> recipient, ObservableList<Center> center){
recipientTableView = new TableView<Recipient>();
gridPane.add(allRecipientDataLabel, 0, 0, 4, 1);
gridPane.add(recipientTableView, 0, 1, 4, 1);
gridPane.add(selectCenterLabel, 0, 3);
gridPane.add(centerChoice, 1, 2, 1, 3);
gridPane.add(assignButton, 2, 2, 1, 3);
gridPane.add(selectAllCheckBox, 0, 4);
gridPane.add(backButton, 3, 2, 1, 3);
allRecipientDataLabel.setFont(titleFont);
GridPane.setHalignment(allRecipientDataLabel, HPos.CENTER);
GridPane.setHalignment(selectAllCheckBox, HPos.CENTER);
GridPane.setHalignment(selectCenterLabel, HPos.CENTER);
recipientTableView.setPrefSize(1366, 600);
assignButton.setPrefSize(265, 70);
backButton.setPrefSize(265, 70);
centerChoice.setPrefSize(705, 70);
TableColumn<Recipient, CheckBox> selectColumn = new TableColumn<>("Select");
TableColumn<Recipient, Integer> idColumn = new TableColumn<>("ID");
TableColumn<Recipient, String> nameColumn = new TableColumn<>("Name");
TableColumn<Recipient, Integer> ageColumn = new TableColumn<>("Age");
TableColumn<Recipient, String> phoneColumn = new TableColumn<>("Phone");
TableColumn<Recipient, String> centerColumn = new TableColumn<>("Assigned Center");
TableColumn<Recipient, String> fDoseStatusColumn = new TableColumn<>("First Dose Status");
TableColumn<Recipient, LocalDate> fDoseDateColumn = new TableColumn<>("First Dose Appointment Date");
TableColumn<Recipient, String> fDoseBatchColumn = new TableColumn<>("First Dose Batch Number");
TableColumn<Recipient, String> sDoseStatusColumn = new TableColumn<>("Second Dose Status");
TableColumn<Recipient, LocalDate> sDoseDateColumn = new TableColumn<>("Second Dose Appointment Date");
TableColumn<Recipient, String> sDoseBatchColumn = new TableColumn<>("Second Dose Batch Number");
selectColumn.setCellValueFactory(new PropertyValueFactory<>("select"));
idColumn.setCellValueFactory(new PropertyValueFactory<>("id"));
nameColumn.setCellValueFactory(new PropertyValueFactory<>("name"));
ageColumn.setCellValueFactory(new PropertyValueFactory<>("age"));
phoneColumn.setCellValueFactory(new PropertyValueFactory<>("phone"));
centerColumn.setCellValueFactory(new PropertyValueFactory<>("center"));
fDoseStatusColumn.setCellValueFactory(new PropertyValueFactory<>("fDoseStatus"));
fDoseDateColumn.setCellValueFactory(new PropertyValueFactory<>("fDoseDate"));
fDoseBatchColumn.setCellValueFactory(new PropertyValueFactory<>("fDoseBatch"));
sDoseStatusColumn.setCellValueFactory(new PropertyValueFactory<>("sDoseStatus"));
sDoseDateColumn.setCellValueFactory(new PropertyValueFactory<>("sDoseDate"));
sDoseBatchColumn.setCellValueFactory(new PropertyValueFactory<>("sDoseBatch"));
selectColumn.setStyle( "-fx-alignment: CENTER");
for(int i = 0; i < recipient.size(); i++){
recipient.get(i).initialiseCheckBox();
}
recipientTableView.setItems(recipient);
recipientTableView.getColumns().addAll(selectColumn, idColumn, nameColumn, ageColumn, phoneColumn, centerColumn, fDoseStatusColumn, fDoseDateColumn, fDoseBatchColumn, sDoseStatusColumn, sDoseDateColumn, sDoseBatchColumn);
centerChoice.getItems().clear();
centerChoice.getItems().add("N/A");
centerChoice.setValue("N/A");
for(int i = 0; i < center.size(); i++){
centerChoice.getItems().add(center.get(i).getName());
}
selectAllCheckBox.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
if(selectAllCheckBox.isSelected()){
for(int i=0; i<recipient.size(); i++){
recipient.get(i).getSelect().setSelected(true);
}
}
else{
for(int i=0; i<recipient.size(); i++){
recipient.get(i).getSelect().setSelected(false);
}
}
}
});
assignButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
Boolean assignSuccessBool = false;
for(int i = 0; i < recipient.size(); i++){
if(recipient.get(i).getSelect().isSelected()){
recipient.get(i).setCenter(centerChoice.getValue());
assignSuccessBool = true;
recipient.get(i).getSelect().setSelected(false);
selectAllCheckBox.setSelected(false);
}
}
if(assignSuccessBool){
util.save(recipient, center);
util.load(recipient, center);
Stage assignSuccess = new Stage();
assignSuccess.setTitle("Success");
assignSuccess.setResizable(false);
assignSuccess.initModality(Modality.APPLICATION_MODAL);
assignSuccess.initOwner(stage);
VBox assignSuccessVBox = new VBox(20);
assignSuccessVBox.getChildren().add(new Text("Assigned Successfully!"));
assignSuccessVBox.getChildren().add(okButton);
assignSuccessVBox.setAlignment(Pos.CENTER);
Scene assignSuccessScene = new Scene(assignSuccessVBox, 300, 200);
assignSuccess.setScene(assignSuccessScene);
assignSuccess.show();
okButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
assignSuccess.close();
}
});
}else{
Stage assignUnsuccess = new Stage();
assignUnsuccess.setTitle("Unsuccess");
assignUnsuccess.setResizable(false);
assignUnsuccess.initModality(Modality.APPLICATION_MODAL);
assignUnsuccess.initOwner(stage);
VBox assignUnsuccessVBox = new VBox(20);
assignUnsuccessVBox.getChildren().add(new Text("No Recipient Is Assigned."));
assignUnsuccessVBox.getChildren().add(okButton);
assignUnsuccessVBox.setAlignment(Pos.CENTER);
Scene assignUnsuccessScene = new Scene(assignUnsuccessVBox, 300, 200);
assignUnsuccess.setScene(assignUnsuccessScene);
assignUnsuccess.show();
okButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
assignUnsuccess.close();
}
});
}
}
});
backButton.setOnAction(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent arg0) {
try {
GridPane mohProfilePane = new GridPane();
createScene(mohProfilePane);
MOHProfile(stage, mohProfilePane, recipient, center);
loadScene(stage, mohProfilePane);
} catch (Exception e) {
System.out.println("Error: " + e);
}
}
});
}
And these are the codes of the Recipient class
import javafx.scene.control.CheckBox;
/**
* Recipient Class
*/
public class Recipient {
//__________________________________________________________________________________________________________________________________________________________________________________
// Data Field
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
private int id;
private int age;
private String name;
private String phone;
private String fDoseStatus;
private String sDoseStatus;
private String fDoseBatch;
private String sDoseBatch;
private String center;
private LocalDate fDoseDate;
private LocalDate sDoseDate;
private CheckBox select;
//__________________________________________________________________________________________________________________________________________________________________________________
// Constructor
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
/**
* Default Constructor
*/
public Recipient(){}
/**
* Constructor specifying ID, Age, Name, Phone Number.
*
* @param age
* @param name
* @param phone
*/
public Recipient(int id, int age, String name, String phone){
this.id = id;
this.age = age;
this.name = name;
this.phone = phone;
this.center = "N/A";
this.fDoseStatus = "Pending";
this.fDoseBatch = "N/A";
this.sDoseStatus = "Pending";
this.sDoseBatch = "N/A";
this.fDoseDate = LocalDate.parse("0000-01-01");
this.sDoseDate = LocalDate.parse("0000-01-01");
}
//__________________________________________________________________________________________________________________________________________________________________________________
// Mutator
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
/**
* Set Recipient ID.
*
* @param id
*/
public void setId(int id){
this.id = id;
}
/**
* Set Recipient Age.
*
* @param age
*/
public void setAge(int age){
this.age = age;
}
/**
* Set Recipient Name.
*
* @param name
*/
public void setName(String name){
this.name = name;
}
/**
* Set Recipient Phone Number.
*
* @param phone
*/
public void setPhone(String phone){
this.phone = phone;
}
/**
* Set Recipient First Dose Status.
*
* @param fDoseStatus
*/
public void setFDoseStatus(String fDoseStatus){
this.fDoseStatus = fDoseStatus;
}
/**
* Set Recipient Second Dose Status.
*
* @param sDoseStatus
*/
public void setSDoseStatus(String sDoseStatus){
this.sDoseStatus = sDoseStatus;
}
/**
* Set Recipient First Dose Vaccine Batch Number
*
* @param fDoseBatch
*/
public void setFDoseBatch(String fDoseBatch){
this.fDoseBatch = fDoseBatch;
}
/**
* Set Recipient Second Dose Vaccine Batch Number
*
* @param sDoseBatch
*/
public void setSDoseBatch(String sDoseBatch){
this.sDoseBatch = sDoseBatch;
}
/**
* Set Recipient Assigned Center.
*
* @param center
*/
public void setCenter(String center){
this.center = center;
}
/**
* Set Recipient First Dose Appointment Date.
*
* @param fDoseDate
*/
public void setFDoseDate(LocalDate fDoseDate){
this.fDoseDate = fDoseDate;
}
/**
* Set Recipient Second Dose Appointment Date.
*
* @param sDoseDate
*/
public void setSDoseDate(LocalDate sDoseDate){
this.sDoseDate = sDoseDate;
}
/**
* Set CheckBox for Assigning.
*
* @param select
*/
public void setSelect(CheckBox select){
this.select = select;
}
//__________________________________________________________________________________________________________________________________________________________________________________
// Accessor
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
/**
* Get Recipient ID.
*
* @return id
*/
public int getId(){
return id;
}
/**
* Get Recipient Age.
*
* @return age
*/
public int getAge(){
return age;
}
/**
* Get Recipient Name.
*
* @return name
*/
public String getName(){
return name;
}
/**
* Get Recipient Phone Number.
*
* @return phone
*/
public String getPhone(){
return phone;
}
/**
* Get Recipient First Dose Status.
*
* @return fDoseStatus
*/
public String getFDoseStatus(){
return fDoseStatus;
}
/**
* Get Recipient Second Dose Status.
*
* @return sDoseStatus
*/
public String getSDoseStatus(){
return sDoseStatus;
}
/**
* Get Recipient First Dose Vaccine Batch Number
*
* @return fDoseBatch
*/
public String getFDoseBatch(){
return fDoseBatch;
}
/**
* Get Recipient Second Dose Vaccine Batch Number
*
* @return sDoseBatch
*/
public String getSDoseBatch(){
return sDoseBatch;
}
/**
* Get Recipient Assigned Center.
*
* @return center
*/
public String getCenter(){
return center;
}
/**
* Get Recipient First Dose Appointment Date.
*
* @return fDoseDate
*/
public LocalDate getFDoseDate(){
return fDoseDate;
}
/**
* Get Recipient Second Dose Appointment Date.
*
* @return sDoseDate
*/
public LocalDate getSDoseDate(){
return sDoseDate;
}
/**
* Get CheckBox for Assigning.
*
* @return select
*/
public CheckBox getSelect(){
return select;
}
//__________________________________________________________________________________________________________________________________________________________________________________
// Accessor
//‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾‾
/**
* Initialise CheckBox
*/
public void initialiseCheckBox(){
this.select = new CheckBox();
}
}
Solution
If you want to do this with minimal disruption to the rest of your code, then I recommend putting this logic in a custom cell implementation. Here's an example:
import java.time.LocalDate;
import javafx.application.Application;
import javafx.beans.property.ObjectProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.TableCell;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.stage.Stage;
public class Main extends Application {
@Override
public void start(Stage primaryStage) {
var table = new TableView<Recipient>();
table.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
table.getItems().addAll(
new Recipient("Recipient #1", LocalDate.of(0, 1, 1)),
new Recipient("Recipient #2", LocalDate.of(2021, 4, 23)),
new Recipient("Recipient #3", LocalDate.of(2020, 8, 30)),
new Recipient("Recipient #4", LocalDate.of(0, 1, 1)),
new Recipient("Recipient #5", LocalDate.of(2022, 1, 5))
);
var nameCol = new TableColumn<Recipient, String>("Name");
nameCol.setCellValueFactory(data -> data.getValue().nameProperty());
table.getColumns().add(nameCol);
var doseCol = new TableColumn<Recipient, LocalDate>("First Dose");
doseCol.setCellValueFactory(data -> data.getValue().firstDoseDateProperty());
// Use custom cell implementation to display "N/A" for 0000-01-01
doseCol.setCellFactory(tc -> new TableCell<>() {
@Override protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (empty || item == null) {
setText(null);
} else if (item.equals(LocalDate.of(0, 1, 1))) {
// Might want to store 'LocalDate.of(0, 1, 1)' in a field to
// avoid creating an object every time 'updateItem' is invoked
setText("N/A");
} else {
setText(item.toString());
}
}
});
table.getColumns().add(doseCol);
primaryStage.setScene(new Scene(table, 800, 600));
primaryStage.show();
}
public static class Recipient {
private final StringProperty name = new SimpleStringProperty(this, "name");
public final void setName(String name) { this.name.set(name); }
public final String getName() { return name.get(); }
public final StringProperty nameProperty() { return name; }
private final ObjectProperty<LocalDate> firstDoseDate = new SimpleObjectProperty<>(this, "firstDoseDate");
public final void setFirstDoseDate(LocalDate firstDoseDate) { this.firstDoseDate.set(firstDoseDate); }
public final LocalDate getFirstDoseDate() { return firstDoseDate.get(); }
public final ObjectProperty<LocalDate> firstDoseDateProperty() { return firstDoseDate; }
public Recipient() {}
public Recipient(String name, LocalDate firstDoseDate) {
setName(name);
setFirstDoseDate(firstDoseDate);
}
}
}
You can refactor the anonymous TableCell
subclass into a named class if you want to reuse the implementation for multiple columns.
I also recommend you avoid using PropertyValueFactory
. That class was added during a time before lambda expressions were added to Java in version 8. To help developers avoid having to write verbose anonymous classes everywhere, they added classes such as PropertyValueFactory
. However, it has two disadvantages: it relies on reflection and, more importantly, you lose compile-time validations (e.g., whether the property actually exists in the model class).
You should use lambda expressions instead. You can see examples of this approach in the above code. Of course, this works better if your model class exposes JavaFX properties. Your version of Recipient
does not, but you can change the lambda expression to wrap the return value in a property.
Answered By - Slaw
Answer Checked By - Senaida (JavaFixing Volunteer)