javafxdatepickertableviewnewrow

DatePicker's value keeps resetting in Tableview's rows in Javafx


I am using a DatePickerCell class to create Datepicker in a TableView cell, but I'm unable to keep its value.

This is the DatePickerCell class used to render the cell, it was taken from a forum with the birthday example.

public class DatePickerCell<S, T> extends TableCell<T, Date> {

private DatePicker datePicker;

public DatePickerCell() {

    super();

    if (datePicker == null) {
        createDatePicker();
    }
    setGraphic(datePicker);
    setContentDisplay(ContentDisplay.GRAPHIC_ONLY);

    Platform.runLater(new Runnable() {
        @Override
        public void run() {
            datePicker.requestFocus();
        }
    });
}

@Override
public void updateItem(Date item, boolean empty) {

    super.updateItem(item, empty);

    SimpleDateFormat smp = new SimpleDateFormat("dd/MM/yyyy");

    if (null == this.datePicker) {
        System.out.println("datePicker is NULL");
    }

    if (empty) {
        setText(null);
        setGraphic(null);
    } else {

        if (isEditing()) {
            setContentDisplay(ContentDisplay.TEXT_ONLY);

        } else {
            setDatepikerDate(smp.format(new Date()));
            setText(smp.format(new Date()));
            setGraphic(this.datePicker);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }
    }
}

private void setDatepikerDate(String dateAsStr) {

    LocalDate ld = null;
    int day, month, year;

    day = month = year = 0;
    try {
        day = Integer.parseInt(dateAsStr.substring(0, 2));
        month = Integer.parseInt(dateAsStr.substring(3, 5));
        year = Integer.parseInt(dateAsStr.substring(6, dateAsStr.length()));
    } catch (NumberFormatException e) {
        System.out.println("setDatepikerDate / unexpected error " + e);
    }

    ld = LocalDate.of(year, month, day);
    datePicker.setValue(ld);
}

private void createDatePicker() {
    this.datePicker = new DatePicker();
    datePicker.setPromptText("dd/MM/yyyy");
    datePicker.setEditable(true);

    datePicker.setOnAction(t -> {
        LocalDate date = datePicker.getValue();
        int index1 = getIndex();

        SimpleDateFormat smp = new SimpleDateFormat("dd/MM/yyyy");
        Calendar cal = Calendar.getInstance();
        cal.set(Calendar.DAY_OF_MONTH, date.getDayOfMonth());
        cal.set(Calendar.MONTH, date.getMonthValue() - 1);
        cal.set(Calendar.YEAR, date.getYear());

        setText(smp.format(cal.getTime()));
        commitEdit(cal.getTime());
    });

    setAlignment(Pos.CENTER);
}

@Override
public void startEdit() {
    super.startEdit();
}

@Override
public void cancelEdit() {
    super.cancelEdit();
    setContentDisplay(ContentDisplay.TEXT_ONLY);
}

public DatePicker getDatePicker() {
    return datePicker;
}

public void setDatePicker(DatePicker datePicker) {
    this.datePicker = datePicker;
}

}

What I want to know is when I am using it in table and try to add one or more rows, the previously picked dates on previous rows sets to the default (system date) date and my picked values are gone. I can't understand why is it re-initializing all datepickers or resetting their dates.

This is how I am using it in my code

@FXML private TableView<Stock> tblStock;
@FXML private TableColumn<Stock, Date> colDate;

colDate.setCellValueFactory(new PropertyValueFactory<>("date1"));
    colDate.setCellFactory(cell -> new DatePickerCell());

In my Stock class, this is how I'm initializing date1

private Date date1 = new Date();

Solution

  • Finally, after a long long searching I was able to achieve my goal. Thanks to this person, I got a working table cell with datepicker.

    Here is the code for future reference:

    DatePickerCell class

    public class DatePickerCell<S, T> extends TableCell<S, Date> {
    
    private DatePicker datePicker;
    
    public DatePickerCell() {
    
        super();
    
        //if you want focus on your datepicker
        /*Platform.runLater(new Runnable() {
            @Override
            public void run() {
                datePicker.requestFocus();
            }
        });*/
    }
    
    @Override
    public void updateItem(Date item, boolean empty) {
        super.updateItem(item, empty);
    
        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
    
            if (isEditing()) {
                if(datePicker != null) {
                    datePicker.setValue(getDate());
                }
                setText(null);
                setGraphic(datePicker);
            } else {
                 setText(getDate()
              .format(DateTimeFormatter.ofLocalizedDate(FormatStyle.SHORT)));
                setGraphic(null);
            }
        }
    }
    
    private void createDatePicker() {
        this.datePicker = new DatePicker(getDate());
        datePicker.setPromptText("dd/MM/yyyy");
        datePicker.setEditable(true);
    
        datePicker.setOnAction(t -> {
    commitEdit(Date.from(datePicker.getValue().atStartOfDay(ZoneId.systemDefault())
    .toInstant()));
    
        datePicker.focusedProperty().addListener(((observable, oldValue,
           newValue) -> {
                if(!newValue)
                    commitEdit(Date.from(datePicker.getValue()
                .atStartOfDay(ZoneId.systemDefault()).toInstant()));
            }));
        });
    }
    
    @Override
    public void startEdit() {
        super.startEdit();
        if(!isEmpty()) {
            createDatePicker();
            setText(null);
            setGraphic(datePicker);
        }
    }
    
    @Override
    public void cancelEdit() {
        super.cancelEdit();
    
        setText(getDate().toString());
        setGraphic(null);
    }
    
    public LocalDate getDate() {
        return getItem() == null ? LocalDate.now() :
         getItem().toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }
    
    }
    

    Using in app

    Model class

    private SimpleObjectProperty<Date> date = new SimpleObjectProperty<>(/*your parameter*/);
    
    //getter
    public Date getDate() {
        return date.get();
    }
    
    //property getter
    public SimpleObjectProperty<Date> dateProperty() {
        return date;
    }
    
    //setter
    public void setDate(Date date) {
        this.date.set(date);
    }
    

    Controller

    @FXML private TableColumn<Stock, Date> colDate;
    
    //because using FXML document, initialization not needed
    
    colDate.setCellValueFactory(cell -> cell.getValue().dateProperty());
    
    colDate.setCellFactory(cell -> new DatePickerCell<Stock, Date>());
    
    colDate.setOnEditCommit(event -> event.getTableView().getItems()
       .get(event.getTablePosition().getRow()).setDate(event.getNewValue()));
    

    Hope this helps in future.