---
category: swing
folder: TableCellSelectionListener
title: JTableのセル選択をテストする
tags: [JTable, ListSelectionListener]
author: aterai
pubdate: 2018-02-26T17:40:02+09:00
description: JTableの行と列のSelectionModelにListSelectionListenerを追加し、選択されたセルの情報を書き出すテストを行っています。
image: https://drive.google.com/uc?id=1d_wUBKZrFO5wKccZ3b2qiE0J8zKc-Q9QVQ
---
* 概要 [#summary]
`JTable`の行と列の`SelectionModel`に`ListSelectionListener`を追加し、選択されたセルの情報を書き出すテストを行っています。

#download(https://drive.google.com/uc?id=1d_wUBKZrFO5wKccZ3b2qiE0J8zKc-Q9QVQ)

* サンプルコード [#sourcecode]
#code(link){{
JTable table1 = new JTable(model);
table1.setCellSelectionEnabled(true);
ListSelectionListener selectionListener1 = new AbstractTableCellSelectionListener() {
  @Override public void valueChanged(ListSelectionEvent e) {
    if (e.getValueIsAdjusting()) {
      return;
    }
    int sr = table1.getSelectionModel().getLeadSelectionIndex();
    int sc = table1.getColumnModel().getSelectionModel().getLeadSelectionIndex();
    if (getRowColumnAdjusting(sr, sc)) {
      return;
    }
    Object o = table1.getValueAt(sr, sc);
    textArea.append(String.format("(%d, %d) %s%n", sr, sc, o));
    textArea.setCaretPosition(textArea.getDocument().getLength());
  }
};
table1.getSelectionModel().addListSelectionListener(selectionListener1);
table1.getColumnModel().getSelectionModel().addListSelectionListener(selectionListener1);
// ...
abstract class AbstractTableCellSelectionListener implements ListSelectionListener {
  private int prevRow = -1;
  private int prevCol = -1;
  protected boolean getRowColumnAdjusting(int sr, int sc) {
    boolean flg = prevRow == sr && prevCol == sc;
    prevRow = sr;
    prevCol = sc;
    return flg;
  }
}
}}

* 解説 [#explanation]
- `JTable`
-- `JTable#getSelectionModel()`と`JTable#getColumnModel()#getSelectionModel()`で取得した行と列の`SelectionModel`に共通の`ListSelectionListener`を追加し、選択されたセルの内容と行列番号を表示
-- `JTable#getSelectedRow()`と`JTable#getSelectedColumn()`を使用しているため、KBD{Shift}+クリックなどで範囲選択した場合アンカーインデックスが現在選択しているセルになる
--- 同一セルが選択された場合は選択セルの内容を書き出さないよう設定しているため、これらの範囲選択ではなにも書き出されない
-- KBD{Ctrl+A}で全選択すると、常に`(0, 0)`のセル情報が書き出される(直前に選択されているのが`(0, 0)`の場合は除く)
-- KBD{Ctrl+A}で全選択すると常に`(0, 0)`のセル情報が書き出される(直前に選択されているのが`(0, 0)`の場合は除く)
- `SelectionModel`
-- `JTable#getSelectionModel()`と`JTable#getColumnModel()#getSelectionModel()`で取得した行と列の`SelectionModel`に共通の`ListSelectionListener`を追加し、選択されたセルの内容と行列番号を表示
-- `JTable#getSelectionModel()#getLeadSelectionIndex()`と`JTable#getColumnModel()#getSelectionModel()#getLeadSelectionIndex()`を使用しているため、KBD{Shift}+クリックなどで範囲選択した場合リードインデックスが現在選択しているセルになる
--- 範囲選択するとマウスをリリースした位置のセル情報が書き出される
-- KBD{Ctrl+A}で全選択してもリードインデックスは変化しないため、セル情報は書き出されない
- `Row/Column`
-- `JTable#getSelectionModel()`と`JTable#getColumnModel()#getSelectionModel()`で取得した行と列の`SelectionModel`に別々の`ListSelectionListener`を追加し、選択インデックスを表示
-- 行と列で異なる`ListSelectionListener`を追加しているため、`1`回のマウス選択などで`2`回情報が書き出される場合がある
-- 範囲選択した場合、常に`ListSelectionEvent#getFirstIndex() <= ListSelectionEvent#getLastIndex()`
--- 例えば`(2, 2)`のセルから`(0, 0)`へ範囲選択した場合、`ListSelectionEvent#getFirstIndex()`は`0`、`ListSelectionEvent#getLastIndex()`は`2`
--- アンカーインデックス、リードインデックスを取得する場合は、`ListSelectionModel#getAnchorSelectionIndex()`と`ListSelectionModel#getLeadSelectionIndex()`を使用する
--- アンカーインデックス、リードインデックスを取得する場合は`ListSelectionModel#getAnchorSelectionIndex()`と`ListSelectionModel#getLeadSelectionIndex()`を使用する
- `changeSelection`
-- `JTable#changeSelection(...)`メソッドをオーバーライドして選択セル情報を書き出す
-- 範囲選択中(`ListSelectionEvent#getValueIsAdjusting()`)を除外していないため、マウスでドラッグされたセル情報などもすべて書き出される

* 参考リンク [#reference]
- [[JTableで行を選択>Swing/RowSelection]]
- [[JTableの選択状態を変更>Swing/ChangeSelection]]
- [https://docs.oracle.com/javase/jp/8/docs/api/javax/swing/event/ListSelectionEvent.html#getFirstIndex-- ListSelectionEvent#getFirstIndex() (Java Platform SE 8)]
-- 英語版は`getFirstIndex() <= getLastIndex()`と表示されているが、日本語版は以下のように文字化けしている
 <code>getFirstIndex()&amp;lt;= getLastIndex()</code>
 getFirstIndex()&lt;= getLastIndex()

* コメント [#comment]
#comment
#comment