TITLE:JTableに行ヘッダを追加

Posted by terai at 2006-09-04

JTableに行ヘッダを追加

JTableに行ヘッダを追加を追加します。

  • &jnlp;
  • &jar;
  • &zip;

#screenshot

サンプルコード

class RowHeaderList extends JList {
  private final JTable table;
  private final ListSelectionModel tableSelection;
  private final ListSelectionModel rListSelection;
  public RowHeaderList(ListModel model, JTable table) {
    super(model);
    this.table = table;
    setFixedCellHeight(table.getRowHeight());
    setCellRenderer(new RowHeaderRenderer(table.getTableHeader()));
    RollOverListener rol = new RollOverListener();
    addMouseListener(rol);
    addMouseMotionListener(rol);
    tableSelection = table.getSelectionModel();
    rListSelection = getSelectionModel();
  }
  class RowHeaderRenderer extends JLabel implements ListCellRenderer {
    private final JTableHeader header;
    public RowHeaderRenderer(JTableHeader header) {
      this.header = header;
      this.setOpaque(true);
      //this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
      this.setBorder(BorderFactory.createMatteBorder(0,0,1,2,Color.GRAY));
      this.setHorizontalAlignment(CENTER);
      this.setForeground(header.getForeground());
      this.setBackground(header.getBackground());
      this.setFont(header.getFont());
    }
    public Component getListCellRendererComponent(JList list, Object value,
               int index, boolean isSelected, boolean cellHasFocus) {
      if(index==pressedRowIndex) {
        setBackground(Color.GRAY);
      }else if(index==rollOverRowIndex) {
        setBackground(Color.WHITE);
      }else if(isSelected) {
        setBackground(Color.GRAY.brighter());
      }else{
        setForeground(header.getForeground());
        setBackground(header.getBackground());
      }
      setText((value==null)?"":value.toString());
      return this;
    }
  }
}

解説

上記のサンプルでは、JListで作成した行ヘッダをJScrollPaneにsetRowHeaderViewメソッドで追加しています。

表の余白などに色がついているのは、テストの名残です。特に意味は無いのですが、そのまま残しています。

rowHeader.setBackground(Color.BLUE);
scrollPane.setBackground(Color.RED);
scrollPane.getViewport().setBackground(Color.GREEN);

参考リンク

コメント

  • 不正なセルレンダラーを設定していたので修正しました。 -- terai
  • excelのように、行ヘッダをクリックしてその行が選択されたり、テーブルの本体にてセルをクリックしてそのセルだけが選択されたりすることはできますか?いろいろ試しましたが、なかなかできませんでした。 -- javalover
    • セル選択は、table.setCellSelectionEnabled(true);で可能です。行ヘッダをクリックしてその行を選択することは、現在でも出来るような。もし、列のことなら、JTableHeaderに以下のようなコードを書けばよさそうです。 JTableHeaderをクリックしてそのColumnのセルを全選択を参考にしてください。 -- terai
    • あ、もしかして、TableCellRendererでセルの背景色を変更 の例のように、JTable#prepareRendererをオーバーライドして行ごとの背景色を変更していますか? あちらの例では、行選択しか考慮していなのでisRowSelectedを使って、一行まるごと選択色で塗りつぶすかどうかを判断しています*1が、セル選択する場合は、ちゃんとisCellSelected(int,int)でそのセルが選択されているかを判断する必要があります。 -- terai
  • ここのサンプルを変更して、行列ヘッダクリックで、各行列を選択するように変更しました。 -- terai
  • プログラム自体大学で始めて触れてる者で参考にさせてもらっています。 -- D.Umeda(ES)
  • すいません、上のミスです。改行と思ってEnterKeyを..。DefaultTableCellRenderer r1 = (DefaultTableCellRenderer)table.getTableHeader().getDefaultRenderer()をした上でこのr1を必要なColumにsetCellRendererしてやれば凡その機能は再現できるのではないでしょうか?Ver1.6環境Vistaで実行しましたが、オンマウス時の背景変化以外は全て実装できているように思います。JScrollPaneに対してJPanelを追加、その上にテーブルヘッダを1行ずつ追加していけばVista仕様でもXP仕様でもオンマウスの変化を再現できますが、Vistaの場合、グラフィックの問題で1pxずれる上、結局リスナを設定しなければヘッダ選択による行の全選択が出来ないので前者の方が効率が良いですが。逐一ヘッダを作って張ってなので後者は処理速度的にも実装形式的にも非効率だと思われます。ちなみにDefaultでもTableCellRendererでもVista上では結果は同じでWindowsClassicが適応されているように見えます。多々間違いがあれば訂正か削除をお願いします。長文、ミス失礼しました。 -- D.Umeda(ES)
    • どうもです。多分以下のような提案だと思っているのですが、合ってます? 処理速度とかは、この程度のサンプルだと、どちらもあまり気にしなくてもいいと思います。 -- terai
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class HeaderRendererTest{
  public JComponent makeUI() {
    String[] columnNames = {"", "String", "Boolean"};
    Object[][] data = {
      {0, "AAA", true}, {1, "BBB", false},
    };
    DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
    };
    JTable table = new JTable(model);
    table.setRowSelectionAllowed(true);
    table.setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION);

    JTableHeader header = table.getTableHeader();
    header.setReorderingAllowed(false);

    TableCellRenderer hr = header.getDefaultRenderer();
    TableColumn col = table.getColumnModel().getColumn(0);
    col.setCellRenderer(new HeaderRenderer(table, hr));

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    p.setPreferredSize(new Dimension(320, 160));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    try{
      UIManager.setLookAndFeel(
        UIManager.getSystemLookAndFeelClassName());
    }catch(Exception e) {
      e.printStackTrace();
    }
    JFrame frame = new JFrame();
    frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    frame.getContentPane().add(new HeaderRendererTest().makeUI());
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}
class HeaderRenderer implements TableCellRenderer {
  private final TableCellRenderer tcr;
  public HeaderRenderer(JTable table, TableCellRenderer tcr) {
    this.tcr  = tcr;
    RollOverListener rol = new RollOverListener();
    table.addMouseListener(rol);
    table.addMouseMotionListener(rol);
  }
  public Component getTableCellRendererComponent(
    JTable tbl, Object val, boolean isS,
    boolean hasF, int row, int col) {
    JLabel l;
    boolean flg = (row==rollOverRowIndex);
    l = (JLabel)tcr.getTableCellRendererComponent(
      tbl, val, isS, flg?flg:hasF, row, col);
    l.setOpaque(!flg);
    return l;
  }
  private int rollOverRowIndex = -1;
  private class RollOverListener extends MouseInputAdapter {
    public void mouseExited(MouseEvent e) {
      rollOverRowIndex = -1;
      JTable table = (JTable)e.getSource();
      table.repaint();
    }
    public void mouseMoved(MouseEvent e) {
      JTable table = (JTable)e.getSource();
      Point pt = e.getPoint();
      int column = table.columnAtPoint(pt);
      rollOverRowIndex = (column==0)?table.rowAtPoint(pt):-1;
      table.repaint();
    }
    public void mouseDragged(MouseEvent e) {}
    public void mousePressed(MouseEvent e) {}
    public void mouseReleased(MouseEvent e) {}
  }
}