TL;DR version: you are confusing the cellValueFactory
with the cellFactory
. See, for example, this tutorial for a nice explanation of the difference, which is summarized for this particular example below.
A table column's cellValueFactory
is an object that tells the column which values to display in the cells, or more precisely how to get those values from the objects representing each row. This is represented by a Callback<CellDataFeatures<Holiday, LocalDate>, ObservableProperty<LocalDate>>
, i.e. a function mapping a CellDataFeatures<Holiday, LocalDate>
to an ObservableValue<LocalDate>
. So in Java code you would do
dateColumn.setCellValueFactory(holidayRowData -> holidayRowData.getValue().dateProperty());
or, if you prefer to use the (somewhat legacy) PropertyValueFactory
class, you can do
dateColumn.setCellValueFactory(new PropertyValueFactory<>("date"));
The latter version has the (many disadvantages, but the one) advantage that it can be done in FXML as well. Note, though, that you want the cellValueFactory
, not the cellFactory
. So your FXML should be
<TableView fx:id="tableView">
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY"/>
</columnResizePolicy>
<columns>
<TableColumn text="Holiday Name">
<cellValueFactory>
<PropertyValueFactory property="name"/>
</cellValueFactory>
</TableColumn>
<TableColumn text="Date">
<cellValueFactory>
<PropertyValueFactory property="date" />
</cellValueFactory>
</TableColumn>
</columns>
</TableView>
The cellFactory
, by contrast, is an object that tells the column how to display the data. It is represented by a Callback<TableColumn<Holiday, LocalDate>, TableCell<Holiday, LocalDate>>
, i.e a function mapping a TableColumn<Holiday, LocalDate>
to a TableCell<Holiday, LocalDate>
. The ClassCastException
occurs because the cell factory you set is going to be passed the TableColumn
, but is expecting to receive a CellDataFeatures
, and so when it tries to treat it as such, the cast fails.
You may well want a cell factory here, in addition to the cell value factory, so that you can control how the date is displayed (e.g. control the format used for it). If you give the date column an fx:id
, say <TableColumn fx:id="dateColumn">
, and inject it into the controller with
@FXML
private TableColumn<Holiday, LocalDate> dateColumn ;
then in the controller's initialize method, you can do:
public void initialize() throws IOException {
data = new HolidayData();
data.loadHolidays();
tableView.setItems(data.getHolidays());
DateTimeFormatter formatter = DateTimeFormatter.ofPattern("dd-MM-yyyy");
dateColumn.setCellFactory(column -> new TableCell<Holiday, LocalDate>() {
@Override
protected void updateItem(LocalDate date, boolean empty) {
super.updateItem(date, empty);
if (empty) {
setText("");
} else {
setText(formatter.format(date));
}
}
});
}