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