• category: swing folder: RowHeaderStyle title: JTableの行ヘッダに列ヘッダのRendererを使用する tags: [JTable, JTableHeader, TableCellRenderer, Icon] author: aterai pubdate: 2012-11-05T14:47:06+09:00 description: JTableの行の描画に、JTableHeaderから取得した列ヘッダのRendererを適用します。 image: https://lh3.googleusercontent.com/-FSdrv2BDUCo/UJaJTUVXcdI/AAAAAAAABWU/gBeKokda9h8/s800/RowHeaderStyle.png

概要

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)で表示

参考リンク

コメント