Summary

JTableHeaderの各カラムにHeaderRendererを設定し、その曜日に応じた文字列と背景色でヘッダセルを描画します。

Source Code Examples

class MonthTable extends JTable {
  @Override public void updateUI() {
    super.updateUI();
    JTableHeader header = getTableHeader();
    header.setResizingAllowed(false);
    header.setReorderingAllowed(false);
    updateWeekHeaderRenderer();
  }

  @Override protected JTableHeader createDefaultTableHeader() {
    return new JTableHeader(columnModel) {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        d.height = 24;
        return d;
      }
    };
  }

  @Override public void setModel(TableModel dataModel) {
    super.setModel(dataModel);
    EventQueue.invokeLater(this::updateWeekHeaderRenderer);
  }

  private void updateWeekHeaderRenderer() {
    TableColumnModel cm = getColumnModel();
    TableCellRenderer r = new WeekHeaderRenderer();
    for (int i = 0; i < cm.getColumnCount(); i++) {
      cm.getColumn(i).setHeaderRenderer(r);
    }
    getTableHeader().repaint();
  }
// ...
}

class WeekHeaderRenderer extends DefaultTableCellRenderer {
  public static final Color SUNDAY_BGC = new Color(0xB0_12_1A);
  public static final Color SATURDAY_BGC = new Color(0x1A_12_B0);
  private final WeekFields weekFields = WeekFields.of(Locale.getDefault());

  @Override public Component getTableCellRendererComponent(
        JTable table, Object value, boolean isSelected, boolean hasFocus,
        int row, int column) {
    Component c = super.getTableCellRendererComponent(
        table, value, isSelected, hasFocus, row, column);
    DayOfWeek week = weekFields.getFirstDayOfWeek().plus(column);
    if (week.equals(DayOfWeek.SUNDAY)) {
      c.setForeground(table.getSelectionForeground());
      c.setBackground(SUNDAY_BGC);
    } else if (week.equals(DayOfWeek.SATURDAY)) {
      c.setForeground(table.getSelectionForeground());
      c.setBackground(SATURDAY_BGC);
    } else {
      c.setForeground(table.getForeground());
      c.setBackground(table.getTableHeader().getBackground());
    }
    if (c instanceof JLabel) {
      JLabel l = (JLabel) c;
      l.setHorizontalAlignment(CENTER);
      Color gridColor = UIManager.getColor("Table.gridColor");
      Border border = BorderFactory.createMatteBorder(0, 0, 1, 1, gridColor);
      Border b = BorderFactory.createCompoundBorder(border, l.getBorder());
      l.setBorder(b);
    }
    return c;
  }
}
View in GitHub: Java, Kotlin

Description

  • DefaultTableCellRendererを継承する曜日表示用のセルレンダラーを作成
    • DefaultTableCellRenderer#getTableCellRendererComponent(...)をオーバーライドして、現在描画する列が土曜、日曜、それ以外かをWeekFields.of(Locale.getDefault()).getFirstDayOfWeek().plus(column)で調査して背景色を設定
    • カレンダーの曜日表示用のJTableHeaderからTableColumnを取得し、すべてに上記のセルレンダラーを設定
      • このサンプルのJTableではautoCreateColumnsFromModeltrueで、表示する月やLookAndFeelの変更でモデル変更されるとそれに合わせて列モデルも新規作成するため、JTable#setModel(...)をオーバーライドしてその内部で上記のセルレンダラーを再設定している
      • 土日平日用に3種類のTableCellRendererを作成して対応するTableColumnに設定する方法もある
  • JViewportの高さを基準にJTableHeaderの高さを調整していたので、JTableの行の高さ調整と競合してループする場合があった? → JTableHeaderの高さを固定して表示するよう修正

Reference

Comment