概要

JTableの各行の高さ変更することで行数などに変更があっても、JViewportに余白が発生しないように調整します。

サンプルコード

JTable table = new JTable(model) {
  int prevHeight = -1;
  int prevCount = -1;

  private void updateRowsHeight(JViewport vport) {
    int height = vport.getExtentSize().height;
    int rowCount = getModel().getRowCount();
    int defaultRowHeight = height / rowCount;
    if ((height != prevHeight || rowCount != prevCount) && defaultRowHeight > 0) {
      // int remainder = height - rowCount * defaultRowHeight;
      int remainder = height % rowCount;
      for (int i = 0; i < rowCount; i++) {
        int a = remainder > 0 ? i == rowCount - 1 ? remainder : 1 : 0;
        setRowHeight(i, defaultRowHeight + a);
        remainder--;
      }
    }
    prevHeight = height;
    prevCount = rowCount;
  }

  @Override public void doLayout() {
    super.doLayout();
    Container p = SwingUtilities.getAncestorOfClass(JViewport.class, this);
    if (p instanceof JViewport) {
      updateRowsHeight((JViewport) p);
    }
  }
};
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、JViewportのサイズまでJTableの各セルをGridLayout風に同比率で拡大縮小するようJTable#doLayout()メソッドをオーバーライドしています。

  • 余白(高さ方向)の調整
    • JViewportの高さが変更されたり行数の増減が発生した場合、各行の高さをJTable#setRowHeight(...)で設定し直すことでJViewportに余白が生成されないように調整

  • JScrollPaneの高さだけ変更した場合、JTable#doLayout()が呼び出されなくなった?
    • JTable#setFillsViewportHeight(true)を設定しても高さの拡大縮小でJTable#doLayout()が呼び出されない
    • JScrollPaneComponentListenerを追加して回避
      scroll.addComponentListener(new ComponentAdapter() {
        @Override public void componentResized(ComponentEvent e) {
          Component c = e.getComponent();
          if (c instanceof JScrollPane) {
            ((JScrollPane) c).getViewport().getView().revalidate();
          }
        }
      });
      

参考リンク

コメント