---
category: swing
folder: ContinuousMonthlyCalendar
title: JScrollPaneにJTableを配置して連続月間カレンダーを作成する
tags: [JScrollPane, JTable, LocalDate, Calendar]
author: aterai
pubdate: 2023-02-27T01:05:27+09:00
description: JScrollPaneにJTableを配置してマウスホイールなどでスクロール可能な連続月間カレンダーを作成します。
image: https://drive.google.com/uc?id=1t_loMpWjMtdCAC6iCBzebKnkdJoiV7pj
---
* 概要 [#summary]
`JScrollPane`に`JTable`を配置してマウスホイールなどでスクロール可能な連続月間カレンダーを作成します。

#download(https://drive.google.com/uc?id=1t_loMpWjMtdCAC6iCBzebKnkdJoiV7pj)

* サンプルコード [#sourcecode]
#code(link){{
JScrollBar verticalScrollBar = new JScrollBar(Adjustable.VERTICAL) {
  @Override public Dimension getPreferredSize() {
    Dimension d = super.getPreferredSize();
    d.width = 0;
    return d;
  }
};
verticalScrollBar.setUnitIncrement(monthTable.getRowHeight());
scroll.setVerticalScrollBar(verticalScrollBar);
verticalScrollBar.getModel().addChangeListener(e -> {
  EventQueue.invokeLater(() -> {
    JViewport viewport = scroll.getViewport();
    Point pt = SwingUtilities.convertPoint(viewport, 0, 0, monthTable);
    int row = monthTable.rowAtPoint(pt);
    int col = 6; // monthTable.columnAtPoint(pt);
    LocalDate localDate = (LocalDate) monthTable.getValueAt(row, col);
    currentLocalDate = localDate;
    updateMonthLabel(localDate, locale1);
    viewport.repaint();
  });
});
}}

* 解説 [#explanation]
- 表示用の`JTable`や`JTableHeader`、`TableCellRenderer`は[[JTableにLocaleを考慮したLocalDateを適用してカレンダーを表示する>Swing/CalendarViewTable]]とほぼ同じものを使用
-- 行の高さを`32px`固定に変更している
- `TableModel`は`1`月`6`週分の`6`行ではなく、現在の日付から前後`500`週分の`1000`行分保持するよう変更し、スクロールで表示する週を変更可能にしている
-- このため月変更用`JButton`は`TableModel`の入れ替えではなく、以下のように`monthTable.scrollRectToVisible(...)`メソッドを実行して対象となる月の`1`週目が先頭に表示される位置までスクロールするよう変更
#code{{
public void updateMonthView(LocalDate localDate, Locale locale) {
  currentLocalDate = localDate;
  updateMonthLabel(localDate, locale);
  TableModel model = monthTable.getModel();
  int v = model.getRowCount() / 2;
  LocalDate startDate1 = getTopLeftCellDayOfMonth(realLocalDate, locale);
  LocalDate startDate2 = getTopLeftCellDayOfMonth(localDate, locale);
  int between = (int) ChronoUnit.WEEKS.between(startDate1, startDate2);
  Rectangle r = monthTable.getCellRect(v + between, 0, false);
  r.height = scroll.getViewport().getViewRect().height;
  monthTable.scrollRectToVisible(r);
  scroll.repaint();
}
}}

- 縦`JScrollBar`はその幅を`0`に設定して不可視化しているが`MouseWheel`でスクロール可能になるよう設定
-- [[JScrollBarが非表示でもMouseWheelでScrollする>Swing/MouseWheelScroll]]
- 縦`JScrollBar``ChangeListener`を設定し`MouseWheel`などでスクロールしたとき右上隅に表示されるセルの日付の月を取得して月表示`JLabel`に設定
- 縦`JScrollBar`に`ChangeListener`を追加し`MouseWheel`などでスクロールしたとき右上隅に表示されるセルの日付の月を取得して月表示`JLabel`を更新
-- [[JEditorPaneのスクロールに連動してJTreeのノードを選択する>Swing/Scrollspy]]

* 参考リンク [#reference]
- [[JTableにLocaleを考慮したLocalDateを適用してカレンダーを表示する>Swing/CalendarViewTable]]
- [[JScrollBarが非表示でもMouseWheelでScrollする>Swing/MouseWheelScroll]]
- [[JEditorPaneのスクロールに連動してJTreeのノードを選択する>Swing/Scrollspy]]

* コメント [#comment]
#comment
#comment