概要

JTableの行の描画に、JTableHeaderから取得した列ヘッダのRendererを適用します。

サンプルコード

class RowHeaderRenderer extends JLabel implements TableCellRenderer {
  private int rollOverRowIndex = -1;

  public RowHeaderRenderer(JTable table) {
    super();
    RollOverListener rol = new RollOverListener();
    table.addMouseListener(rol);
    table.addMouseMotionListener(rol);
  }

  @Override public Component getTableCellRendererComponent(
      JTable tbl, Object val, boolean isS, boolean hasF, int row, int col) {
    TableCellRenderer tcr = tbl.getTableHeader().getDefaultRenderer();
    boolean f = row == rollOverRowIndex;
    JLabel l = (JLabel) tcr.getTableCellRendererComponent(
        tbl, val, isS, f ? f : hasF, -1, -1);
    if (tcr.getClass().getName().indexOf("XPDefaultRenderer") >= 0) {
      l.setOpaque(!f);
      this.setIcon(new ComponentIcon(l));
      return this;
    } else {
      return l;
    }
  }

  class RollOverListener extends MouseAdapter {
    @Override public void mouseMoved(MouseEvent e) {
      JTable table = (JTable) e.getComponent();
      Point pt = e.getPoint();
      int col = table.columnAtPoint(pt);
      int column = table.convertColumnIndexToModel(col);
      if (column != 0) {
        return;
      }
      int prevRow = rollOverRowIndex;
      rollOverRowIndex = table.rowAtPoint(pt);
      if (rollOverRowIndex == prevRow) {
        return;
      }
      Rectangle repaintRect;
      if (rollOverRowIndex >= 0) {
        Rectangle r = table.getCellRect(rollOverRowIndex, col, false);
        if (prevRow >= 0) {
          repaintRect = r.union(table.getCellRect(prevRow, col, false));
        } else {
          repaintRect = r;
        }
      } else {
        repaintRect = table.getCellRect(prevRow, col, false);
      }
      table.repaint(repaintRect);
    }

    @Override public void mouseExited(MouseEvent e) {
      JTable table = (JTable) e.getComponent();
      Point pt = e.getPoint();
      int col = table.columnAtPoint(pt);
      int column = table.convertColumnIndexToModel(col);
      if (column != 0) {
        return;
      }
      if (rollOverRowIndex >= 0) {
        table.repaint(table.getCellRect(rollOverRowIndex, col, false));
      }
      rollOverRowIndex = -1;
    }
  }
}

class ComponentIcon implements Icon {
  private final JComponent cmp;
  public ComponentIcon(JComponent cmp) {
    this.cmp = cmp;
  }

  @Override public int getIconWidth() {
    return 4000; // Short.MAX_VALUE;
  }

  @Override public int getIconHeight() {
    return cmp.getPreferredSize().height + 4; // XXX: +4 for Windows 7
  }

  @Override public void paintIcon(Component c, Graphics g, int x, int y) {
    SwingUtilities.paintComponent(
        g, cmp, (Container) c, x, y, getIconWidth(), getIconHeight());
  }
}
View in GitHub: Java, Kotlin

解説

上記のサンプルでは、0列目のセルにJTable#getTableHeader()#getDefaultRenderer()メソッドで取得したセルレンダラーを使用するTableCellRendererを適用しています。

  • ソートアイコンが列ヘッダに表示されていても行ヘッダには表示しない
    • 引数の行と列を両方-1に設定して、TableCellRenderer#getTableCellRendererComponent(...)で描画用コンポーネント(JLabel)をヘッダセルレンダラーから取得
  • WindowsLookAndFeel
    • ロールオーバーを描画する場合はTableCellRenderer#getTableCellRendererComponent(...)で取得したコンポーネントを透明にする
    • 右と下側に余白が発生するのでヘッダセルレンダラーからサイズを変更したアイコンを作成してJLabel#setIcon(Icon)で表示

参考リンク

コメント