FabSommavilla
FabSommavilla

Reputation: 157

How to add a DatePicker to Tableview with a DatePickerCell

I've add a DatePicker to a TableView with the following class : https://code.google.com/p/javafx-filterable-table-columns/source/browse/src/main/java/thirdparty/eu/schudt/javafx/controls/calendar/DatePicker.java?r=db47db237b3342712aafb693f392d403455d5299

I use a DatePickerCell class to ovveride TableCell. The DatePicker display well in the TableView. But the updateItem method does not work well, it does not update the ObservableList.

What am I missing here? Can anyone faced same problem?

Here is my code :

import java.text.SimpleDateFormat;  
import java.util.Locale;  
import javafx.beans.value.ObservableValue;  
import javafx.geometry.Pos;  
import javafx.scene.control.TableCell;  
import thirdparty.eu.schudt.javafx.controls.calendar.DatePicker;  

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

    private final DatePicker datePicker;  
    private ObservableValue<T> ov;  
    public DatePickerCell() {  
        // Initialize the DatePicker for birthday  
        this.datePicker = new DatePicker(Locale.ENGLISH);  
        this.datePicker.setDateFormat(new SimpleDateFormat("dd/MM/yyyy"));  
        this.datePicker.getCalendarView().todayButtonTextProperty().set("Today");  
        this.datePicker.getCalendarView().setShowWeeks(false);          
        this.datePicker.getStylesheets().add("styles/DatePicker.css");  
        this.setAlignment(Pos.CENTER);  
        this.setGraphic(this.datePicker);  
    }  
    @Override  
    public void updateItem(T item, boolean empty) {  
        super.updateItem(item, empty);  
        setGraphic(this.datePicker);  
    }  
}

And the part of cellFactory in the FXController code :

@FXML  
private TableColumn revueDateCol;  

this.revueDateCol.setCellFactory(new Callback<TableColumn<Revue, Date>, TableCell<Revue, Date>>() {  
        @Override  
        public TableCell<Revue, Date> call(TableColumn<Revue, Date> arg0) {  
            return new DatePickerCell<>();  
        }  
   });

Thank for help.


I've tried to implements this way but when I scroll, the cell return to the original value. Any idea ?

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

    private DatePicker datePicker;

    public DatePickerCell() {
        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);

        if (empty) {
            setText(null);
            setGraphic(null);
        } else {
        if (datePicker != null) {
               datePicker.setSelectedDate(getDate());
        }

            setGraphic(this.datePicker);
            setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
        }
    }

    private void createDatePicker() {
        datePicker = new DatePicker(Locale.FRENCH);
        DateFormat formatter = new SimpleDateFormat("dd/MM/yyyy");
        datePicker.setDateFormat(formatter);
        datePicker.setPromptText("jj/mm/aaaa");
        datePicker.getCalendarView().todayButtonTextProperty().set("Aujourd'hui");
        datePicker.getCalendarView().setShowWeeks(false);
        datePicker.getStylesheets().add("/styles/datePicker.css");

        datePicker.selectedDateProperty().addListener(
                new ChangeListener<Date>() {
                    @Override
                    public void changed(ObservableValue<? extends Date> observable,
                            Date oldValue, Date newValue) {

                        commitEdit(newValue);
                    }
                });

        setAlignment(Pos.CENTER);
    }

    private Date getDate() {
        return datePicker.getSelectedDate() != null ? datePicker.getSelectedDate() : getItem();
    }

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

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

}

Regards,

Upvotes: 1

Views: 10534

Answers (2)

FabSommavilla
FabSommavilla

Reputation: 157

Here's a solution that work. It uses a DatePicker and TableView control with Java 8. The blog post is available here.

import java.text.SimpleDateFormat;
import java.time.LocalDate;
import java.util.Calendar;
import java.util.Date;
import javafx.application.Platform;
import javafx.collections.ObservableList;
import javafx.event.Event;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.control.ContentDisplay;
import javafx.scene.control.DatePicker;
import javafx.scene.control.TableCell;

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

    private DatePicker datePicker;
    private ObservableList<BirthdayEvent> birthdayData;

    public DatePickerCell(ObservableList<BirthdayEvent> listBirthdays) {

        super();

        this.birthdayData = listBirthdays;

        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(item));
                setText(smp.format(item));
                setGraphic(this.datePicker);
                setContentDisplay(ContentDisplay.GRAPHIC_ONLY);
            }
        }
    }

    private void setDatepikerDate(String dateAsStr) {

        LocalDate ld = null;
        int jour, mois, annee;

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

        ld = LocalDate.of(annee, mois, jour);
        datePicker.setValue(ld);
    }

    private void createDatePicker() {
        this.datePicker = new DatePicker();
        datePicker.setPromptText("jj/mm/aaaa");
        datePicker.setEditable(true);

        datePicker.setOnAction(new EventHandler() {
            public void handle(Event t) {
                LocalDate date = datePicker.getValue();
                int index = 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());

                if (null != getBirthdayData()) {
                    getBirthdayData().get(index).setDate(cal.getTime());
                }
            }
        });

        setAlignment(Pos.CENTER);
    }

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

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

    public ObservableList<BirthdayEvent> getBirthdayData() {
        return birthdayData;
    }

    public void setBirthdayData(ObservableList<BirthdayEvent> birthdayData) {
        this.birthdayData = birthdayData;
    }

    public DatePicker getDatePicker() {
        return datePicker;
    }

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

}

Upvotes: 2

Uluk Biy
Uluk Biy

Reputation: 49195

To make the tableView editable, you need to
tableView.setEditable(true).
override the startEdit(), cancelEdit() methods of TableCell.
set the revueDateCol.setOnEditCommit() of the related TableColumn.
invoke commitEdit() when editing has been finished.

The working example is official tutorial for Table View, Example 12-11: Alternative Solution Of Cell Editing.
The first three steps above are almost identical, except that you will be using DatePicker instead of TextField.
The last step can be as:

private void createTextField() {
    datePicker = new DatePicker(Locale.ENGLISH);
    datePicker.setDateFormat(new SimpleDateFormat("dd/MM/yyyy"));
    datePicker.getCalendarView().todayButtonTextProperty().set("Today");
    datePicker.getCalendarView().setShowWeeks(false);
    datePicker.getStylesheets().add("styles/DatePicker.css");
    datePicker.selectedDateProperty().addListener(new ChangeListener<Date>() {
        @Override
        public void changed(ObservableValue<? extends Date> observable, Date oldValue, Date newValue) {
            commitEdit(newValue);
        }
    });
}

Upvotes: 0

Related Questions