TITLE:JTableに行ヘッダを追加
Posted by terai at 2006-09-04

JTableに行ヘッダを追加

JTableに行ヘッダを追加を追加します。
  • category: swing folder: TableRowHeader title: JTableに行ヘッダを追加 tags: [JTable, JList, JScrollPane] author: aterai pubdate: 2006-09-04T01:10:03+09:00 description: JTableを設定したJScrollPaneのRowHeaderViewに、JListで作成した行ヘッダを追加します。 image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTUk9YzW7I/AAAAAAAAAmQ/wjin9CuyfBg/s800/TableRowHeader.png hreflang:
       href: https://java-swing-tips.blogspot.com/2011/01/jtable-rowheader.html
       lang: en

概要

JTableを設定したJScrollPaneRowHeaderViewに、JListで作成した行ヘッダを追加します。

#screenshot

サンプルコード

#spanend
#spandel
class RowHeaderList extends JList {
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
class RowHeaderList<E> extends JList<E> {
#spanend
  private final JTable table;
  private final ListSelectionModel tableSelection;
  private final ListSelectionModel rListSelection;
  public RowHeaderList(ListModel model, JTable table) {
  private int rollOverRowIndex = -1;
  private int pressedRowIndex  = -1;
#spanadd

#spanend
  public RowHeaderList(ListModel<E> model, JTable table) {
    super(model);
    this.table = table;
    setFixedCellHeight(table.getRowHeight());
    setCellRenderer(new RowHeaderRenderer(table.getTableHeader()));
    setCellRenderer(new RowHeaderRenderer<E>(table.getTableHeader()));
    RollOverListener rol = new RollOverListener();
    addMouseListener(rol);
    addMouseMotionListener(rol);
#spanadd

#spanend
    tableSelection = table.getSelectionModel();
    rListSelection = getSelectionModel();
  }
  class RowHeaderRenderer extends JLabel implements ListCellRenderer {
    private final JTableHeader header;
#spanadd

#spanend
  class RowHeaderRenderer<E> extends JLabel
                             implements ListCellRenderer<E> {
    private final JTableHeader header; // = table.getTableHeader();
    public RowHeaderRenderer(JTableHeader header) {
      super();
      this.header = header;
      this.setOpaque(true);
      //this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
      this.setBorder(BorderFactory.createMatteBorder(0,0,1,2,Color.GRAY));
      // this.setBorder(UIManager.getBorder("TableHeader.cellBorder"));
      this.setBorder(BorderFactory.createMatteBorder(
          0, 0, 1, 2, Color.GRAY.brighter()));
      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) {
#spanadd

#spanend
    @Override public Component getListCellRendererComponent(
        JList<? extends E> list, E value, int index,
        boolean isSelected, boolean cellHasFocus) {
      if (index == pressedRowIndex) {
        setBackground(Color.GRAY);
      }else if(index==rollOverRowIndex) {
      } else if (index == rollOverRowIndex) {
        setBackground(Color.WHITE);
      }else if(isSelected) {
      } else if (isSelected) {
        setBackground(Color.GRAY.brighter());
      }else{
      } else {
        setForeground(header.getForeground());
        setBackground(header.getBackground());
      }
      setText((value==null)?"":value.toString());
      setText(Objects.toString(value, ""));
      return this;
    }
  }
  // ...
}

解説

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

解説

上記のサンプルでは、JListで作成した行ヘッダをJScrollPane#setRowHeaderView(...)メソッドで追加しています。 表の余白などに色がついているのは、テストの名残です。特に意味は無いのですが、そのまま残しています。
  • -
  • Corner: JScrollPane.html#setCorner(...)で左上隅などにコンポーネントを設定しておらずJScrollPane自体の背景色(赤)が表示されている
  • Viewport: JTableのセルが存在しない領域はJViewportの背景色(緑)が表示されている
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

コメント