Skip to content
Advertisement

JavaFX TableView with array of TableColumns

I got a TableView<MonthRow> where I want to display each month of the year and its relevant days.

I got those three classes for presentation purposes:

public record DayCell(
        LocalDate date,
        DayType type
) {
    public String nameOfDay() {
        return DateTimeFormatter.ofPattern("EE", Locale.ENGLISH).format(date);
    }
}
public enum DayType {
    COMPASSIONATE_LEAVE("C"),
    EMPTY("E"),
    NOT_ON_PAYROLL("N"),
    QUARANTINE("Q"),
    REGULAR_LEAVE("R"),
    SICK_LEAVE("S"),
    TRAINING("TRG"),
    TRAVEL("T"),
    UNPAID_LEAVE("U");

    private final String shortName;

    DayType(String shortName) {
        this.shortName = shortName;
    }
}
public record MonthRow(
        String name,
        DayCell[] days // amount of days in that specific month
) {
}

And then I create the table content:

public ObservableList<MonthRow> createMonth(int year) {
    MonthRow[] months = new MonthRow[12];
    for (int i = 0; i < months.length; i++) {
        LocalDate date = LocalDate.of(year, i + 1, 1);
        months[i] = new MonthRow(date.getMonth().getDisplayName(TextStyle.FULL, Locale.ENGLISH), createCells(date));
    }

    return FXCollections.observableArrayList(months);
}

public DayCell[] createCells(LocalDate date) {
    DayCell[] cells = new DayCell[date.lengthOfMonth()];

    for (int i = 0; i < cells.length; i++) {
        cells[i] = new DayCell(date.plusDays(i), DayType.EMPTY);
    }

    return cells;
}

Having the ObservableList now for the TableView, I am kinda stuck. I want to have one TableColumn for the month and 31 TableColumns for the DayCells. However, because it’s an array I am not sure how to reflect the cellData of each DayCell into each TableCell. Also, because some months do not have 31 days and therefore, the cells should not show any content for the missing days.

Each cell should show the nameOfDay() content and colouring according to the DayType (will be done in the respective cellFactory at some point).

TableView Example

This might be a completely wrong approach, so please don’t hesitate to guide me towards a different solution.

Advertisement

Answer

You can do something like this:

TableView<MonthRow> table = new TableView<>();
TableColumn<MonthRow, String> monthColumn = new TableColumn<>("Month");
monthColumn.setCellValueFactory(cellData -> new SimpleStringProperty(cellData.getValue().getName()));
table.getColumns().add(monthColumn);

for (int i = 0; i < 31 ; i++) {
    TableColumn<MonthRow, DayCell> dayColumn = new TableColumn<>(Integer.toString(i+1));
    final int index = i ;
    dayColumn.setCellValueFactory(cellData -> {
        MonthRow month = cellData.getValue();
        if (index < month.getDays().size()) {
            return new SimpleObjectProperty<>(month.getDays()[index]);
        } else {
            return new SimpleObjectProperty<>(null);
        }
    });
    dayColumn.setCellFactory(new TableCell<>() {
        @Override
        protected void updateItem(DayCell day, boolean empty) {
            super.updateItem(day, empty);
            if (empty | day == null) {
                setText("");
            } else {
                setText(day.nameOfDay());
            }
        }
    });
    table.getColumns().add(dayColumn);
}

This might be a completely wrong approach

Maybe. Do you need the functionality of a TableView here? E.g. selection of a month (row), etc? Perhaps a simple GridPane inside a ScrollPane would be a more convenient approach; it really depends on your project requirements.

User contributions licensed under: CC BY-SA
3 People found this is helpful
Advertisement