---
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 [#summary]
JTableHeaderとJTableの行の高さの合計が親JScrollPaneの高さを埋めるまで均等に自動拡大・縮小します。
`JTableHeader`と`JTable`の行の高さの合計が親`JScrollPane`の高さを埋めるまで均等に自動拡大・縮小します。
// #en{{Automatically resize the JTableHeader and JTable rows evenly to fill the height of the parent JScrollPane.}}

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

* Source Code Examples [#sourcecode]
#code(link){{
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));
    }
  }

  // ...
}
}}

* Description [#description]
- `JScrollPane`の高さが変更された場合、`JScrollPane#doLayout()`内で`ScrollPaneLayout#layoutContainer(...)`が呼ばれ、`JTableHeader#getPreferredSize()`でヘッダのサイズを取得し、その高さや存在すればスクロールバーの高さなどを除去して`JViewport`の高さが決まる
- このため、このサンプルでは`JTableHeader#getPreferredSize()`をオーバーライドして`JTableHeader`の高さを`JScrollPane`の高さの`1/6`になるよう設定
-- 上記の分母`6`は`JTable`が`5`行と`JTableHeader`が`1`個の合計
-- [[JTableHeaderの高さを変更>Swing/TableHeaderHeight]]
- `JTable`の各行の高さは`JTable#doLayout()`をオーバーライドして`JViewport`の高さを満たすよう調整
-- [[JTableの行高がJViewportの高さに合うまで調整する>Swing/AdjustRowHeightFillsViewport]]
- 以下のように`JScrollPane#doLayout()`をオーバーライドして`JViewport`の高さを決めるまえに`JTableHeader`の高さを調整する方法もある

#code{{
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 [#reference]
- [[JTableHeaderの高さを変更>Swing/TableHeaderHeight]]
- [[JTableの行高がJViewportの高さに合うまで調整する>Swing/AdjustRowHeightFillsViewport]]
- [[JTableHeaderのヘッダカラムセルの背景色を変更>Swing/HeaderColumnBackground]]
-- カレンダー部分は上記のリンク先のサンプルを流用

* Comment [#comment]
#comment
#comment