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();
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.