• category: swing folder: AutoResizeTableHeader title: JTableHeaderと各行の高さを親JScrollPaneが埋まるまで均等に自動調整 title-en: Auto adjusts the heights of JTableHeader and rows evenly to fill the parent JScrollPane tags: [JTable, JTableHeader, JScrollPane, Calendar] author: aterai pubdate: 2025-12-01T00:16:26+09:00 description: JTableHeaderとJTableの行の高さの合計が親JScrollPaneの高さまを埋めるまで均等に自動拡大・縮小します。 summary-jp: JTableHeaderとJTableの行の高さの合計が親JScrollPaneの高さまを埋めるまで均等に自動拡大・縮小します。 summary-en: Automatically resize the JTableHeader and JTable rows evenly to fill the height of the parent JScrollPane. image: https://drive.google.com/uc?id=1sN5ERINi9nhOhb5s5MmYFxwPfFLXt8fs

Summary

JTableHeaderとJTableの行の高さの合計が親JScrollPaneの高さを埋めるまで均等に自動拡大・縮小します。

Source Code Examples

class MonthTable extends JTable {
  @Override protected JTableHeader createDefaultTableHeader() {
    return new JTableHeader(columnModel) {
      @Override public Dimension getPreferredSize() {
        Dimension d = super.getPreferredSize();
        JTable tbl = getTable();
        Container c = SwingUtilities.getAncestorOfClass(JScrollPane.class, tbl);
        if (c instanceof JScrollPane) {
          int rowCount = tbl.getModel().getRowCount() + 1;
          Rectangle r = SwingUtilities.calculateInnerArea((JScrollPane) c, null);
          d.height = Math.max(r.height / rowCount, 24);
        }
        return d;
      }
    };
  }

  @Override public void doLayout() {
    super.doLayout();
    Class<JViewport> clz = JViewport.class;
    Optional.ofNullable(SwingUtilities.getAncestorOfClass(clz, this))
        .filter(clz::isInstance).map(clz::cast)
        .ifPresent(this::updateRowsHeight);
  }

  private void updateRowsHeight(JViewport viewport) {
    int height = viewport.getExtentSize().height;
    int rowCount = getModel().getRowCount();
    int defaultRowHeight = height / rowCount;
    int remainder = height % rowCount;
    for (int i = 0; i < rowCount; i++) {
      int a = defaultRowHeight + Math.min(1, Math.max(0, remainder--));
      setRowHeight(i, Math.max(1, a));
    }
  }

  // ...
}
View in GitHub: Java, Kotlin

Description

  • JScrollPaneの高さが変更された場合、JScrollPane#doLayout()内でScrollPaneLayout#layoutContainer(...)が呼ばれ、JTableHeader#getPreferredSize()でヘッダのサイズを取得し、その高さや存在すればスクロールバーの高さなどを除去してJViewportの高さが決まる
  • このため、このサンプルではJTableHeader#getPreferredSize()をオーバーライドしてJTableHeaderの高さをJScrollPaneの高さの1/6になるよう設定
  • JTableの各行の高さはJTable#doLayout()をオーバーライドしてJViewportの高さを満たすよう調整
  • 以下のようにJScrollPane#doLayout()をオーバーライドしてJViewportの高さを決めるまえにJTableHeaderの高さを調整する方法もある
class MonthScrollPane extends JScrollPane {
  protected MonthScrollPane(Component view) {
    super(view);
  }

  @Override public void updateUI() {
    super.updateUI();
    setVerticalScrollBarPolicy(VERTICAL_SCROLLBAR_NEVER);
  }

  @Override public void doLayout() {
    JTable tbl = (JTable) getViewport().getView();
    int rowCount = tbl.getModel().getRowCount() + 1;
    JTableHeader header = tbl.getTableHeader();
    Dimension d = header.getPreferredSize();
    Rectangle r = SwingUtilities.calculateInnerArea(this, null);
    d.height = Math.max(r.height / rowCount, 24);
    header.setPreferredSize(d);
    super.doLayout();
  }
}

Reference

Comment