概要

JTableHeaderの列幅を自動調整しない場合に発生する余白に疑似ヘッダを描画します。

サンプルコード

class TableHeaderFillerLayerUI extends LayerUI<JScrollPane> {
  private final JTable tempTable = new JTable(
      new DefaultTableModel(new Object[] {""}, 0));
  private final JTableHeader filler = tempTable.getTableHeader();
  private final TableColumn fillerColumn = tempTable
      .getColumnModel().getColumn(0);

  @Override public void paint(Graphics g, JComponent c) {
    super.paint(g, c);
    if (c instanceof JLayer) {
      JScrollPane scroll = (JScrollPane) ((JLayer<?>) c).getView();
      JTable table = (JTable) scroll.getViewport().getView();
      JTableHeader header = table.getTableHeader();

      int width = header.getWidth();
      TableColumnModel cm = header.getColumnModel();
      for (int i = 0; i < cm.getColumnCount(); i++) {
        width -= cm.getColumn(i).getWidth();
      }

      Point pt = SwingUtilities.convertPoint(header, 0, 0, c);
      filler.setLocation(pt.x + header.getWidth() - width, pt.y);
      filler.setSize(width, header.getHeight());
      fillerColumn.setWidth(width);

      SwingUtilities.paintComponent(g, filler, tempTable, filler.getBounds());
    }
  }

  @Override public void installUI(JComponent c) {
    super.installUI(c);
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(AWTEvent.COMPONENT_EVENT_MASK);
    }
  }

  @Override public void uninstallUI(JComponent c) {
    if (c instanceof JLayer) {
      ((JLayer<?>) c).setLayerEventMask(0);
    }
    super.uninstallUI(c);
  }

  @Override protected void processComponentEvent(
      ComponentEvent e, JLayer<? extends JScrollPane> l) {
    Component c = e.getComponent();
    if (c instanceof JTableHeader) {
      l.repaint(((JTableHeader) c).getBounds());
    }
  }
}
View in GitHub: Java, Kotlin

解説

  • 上: デフォルト
    • 列幅の自動調整をAUTO_RESIZE_OFFで無効にしたJTable
  • 下: TableHeaderFiller
    • AUTO_RESIZE_OFFを設定し列幅の自動調整を無効にしたJTableJTableHeaderに余白が発生する場合、そこに疑似ヘッダ列を描画
    • 疑似ヘッダの描画にはJLayerを使用
    • JLayerJTableJTableHeaderではなく親のJScrollPaneに設定
    • JLayerで疑似ヘッダへのMouseEventなどは無効化、JTableHeaderがリサイズされてComponentEventが発生した場合はLayerUI#processComponentEvent(...)をオーバーライドして疑似ヘッダの幅を更新

参考リンク

コメント