概要

JScrollPaneJTableを配置してマウスホイールなどでスクロール可能な連続月間カレンダーを作成します。

サンプルコード

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();
  });
});
View in GitHub: Java, Kotlin

解説

  • 表示用のJTableJTableHeaderTableCellRendererJTableにLocaleを考慮したLocalDateを適用してカレンダーを表示するとほぼ同じものを使用
    • 行の高さを32px固定に変更している
  • TableModel16週分の6行ではなく、現在の日付から前後500週分の1000行分保持するよう変更し、スクロールで表示する週を変更可能にしている
    • このため月変更用JButtonTableModelの入れ替えではなく、以下のようにmonthTable.scrollRectToVisible(...)メソッドを実行して対象となる月の1週目が先頭に表示される位置までスクロールするよう変更
      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();
      }
      

参考リンク

コメント