概要
JList
を使用してカーソルキーで次の週や月に移動したり、週を跨いだLocalDate
日付の範囲選択が可能なカレンダーを作成します。
Screenshot
Advertisement
サンプルコード
public final LocalDate realLocalDate = LocalDate.now();
public LocalDate currentLocalDate;
public final Dimension size = new Dimension(40, 26);
// ...
JLabel yearMonthLabel = new JLabel("", SwingConstants.CENTER);
JList<LocalDate> monthList = new JList<LocalDate>(new CalendarViewListModel(realLocalDate)) {
@Override public void updateUI() {
setCellRenderer(null);
super.updateUI();
setLayoutOrientation(JList.HORIZONTAL_WRAP);
setVisibleRowCount(CalendarViewListModel.ROW_COUNT); // ensure 6 rows in the list
setFixedCellWidth(size.width);
setFixedCellHeight(size.height);
setCellRenderer(new CalendarListRenderer<>());
getSelectionModel().setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);
}
};
// ...
class CalendarViewListModel extends AbstractListModel<LocalDate> {
public static final int ROW_COUNT = 6;
private final LocalDate startDate;
private final WeekFields weekFields = WeekFields.of(Locale.getDefault());
protected CalendarViewListModel(LocalDate date) {
super();
LocalDate firstDayOfMonth = YearMonth.from(date).atDay(1);
int dowv = firstDayOfMonth.get(weekFields.dayOfWeek()) - 1;
startDate = firstDayOfMonth.minusDays(dowv);
}
@Override public int getSize() {
return DayOfWeek.values().length * ROW_COUNT;
}
@Override public LocalDate getElementAt(int index) {
return startDate.plusDays(index);
}
}
View in GitHub: Java, Kotlin解説
カレンダーの週や日付モデルはJTableにLocaleを考慮したLocalDateを適用してカレンダーを表示するとほぼ同じですが、上記のサンプルでは表示にJTable
ではなくJList
を使用しているため左右カーソルキーでの週を跨いだ日付移動などが可能になっています。
JList#setLayoutOrientation(JList.HORIZONTAL_WRAP)
を設定し、セルが水平方向の次に垂直方向の順で並ぶ「ニュースペーパー・スタイル」レイアウトを使用- セルサイズは、
JList#setFixedCellWidth(int)
とJList#setFixedCellHeight(int)
メソッドで固定サイズを使用 - 折り返しセル数は、
JList#setVisibleRowCount(int)
メソッドを使用して表示可能行数を設定することで指定HORIZONTAL_WRAP
を指定したJList
の場合、列数を指定した折り返しはできないため、7
列6
行の固定サイズのカレンダーでJList#setVisibleRowCount(6)
を設定することで常に7
日分の列を表示する
HORIZONTAL_WRAP
を指定したJList
の場合、例えば右カーソルキーで土曜から日曜に移動できないため、デフォルトのselectNextColumn
アクションではなく、以下のようなアクションを使用するようにマッピングを変更- 現在の月内なら
HORIZONTAL_WRAP
を無視して、単純に次の日付に選択状態を移動 - 月表示を変更する必要がある場合は、移動先の月で次の日付に選択状態を移動
monthList.getActionMap().put("selectNextIndex", new AbstractAction() { @Override public void actionPerformed(ActionEvent e) { int index = monthList.getLeadSelectionIndex(); if (index < monthList.getModel().getSize() - 1) { monthList.setSelectedIndex(index + 1); } else { LocalDate d = monthList.getModel() .getElementAt(monthList.getModel().getSize() - 1) .plusDays(1); updateMonthView(currentLocalDate.plusMonths(1)); monthList.setSelectedValue(d, false); } } });
- 現在の月内なら
参考リンク
- JTableにLocaleを考慮したLocalDateを適用してカレンダーを表示する
- JListでウィークカレンダーを作成してヒートマップを表示する
- セルが垂直方向の次に水平方向の順で並ぶ「ニュースペーパー・スタイル」レイアウトの
JList
で週カレンダーを表示
- セルが垂直方向の次に水平方向の順で並ぶ「ニュースペーパー・スタイル」レイアウトの