TITLE:TableRowSorterでJTableのソート
#navi(../)
*TableRowSorterでJTableのソート [#m6d46918]
Posted by [[terai]] at 2007-02-12

#contents

**概要 [#ie7bf043]
JDK 6 で導入された、TableRowSorterを利用して、JTableの行を降順、昇順にソートします。

-&jnlp;
-&jar;
-&zip;

#screenshot

**サンプルコード [#ibb86eb9]
#code{{
TestModel model = new TestModel();
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
}}

**解説 [#fbc5127f]
JDK 6 では、JTableにTableRowSorterを設定することで、カラムヘッダのクリックによる行ソートが行えます。

TableRowSorterのデフォルトでは、ヘッダクリックで(降順、昇順)とソートが切り替わり、TableSorterのように(降順、昇順、初期状態)ではなくなっています。上記のサンプルでは、下のボタンをクリックすると、DefaultRowSorter#setSortKeys(List)にnullを代入することで初期状態に戻るようにしていますが、SwingLabsのJXTableみたいにShift+ヘッダクリックで初期状態に戻るようにしてもいいかもしれません(参考:[[TableRowSorterのSortKeysをクリアする>Swing/ClearSortingState]])。

また、DefaultRowSorter#setSortable(int, boolean)でソートしたくないカラムを以前より簡単に指定できます(参考:[[JTableHeaderのカラムを選択不可にする>Swing/DisabledHeader]])。

%%第二キーを使ったソートはTableRowSorter版では出来ない?ようなので、TableSorter.javaを使う場合もまだあるかもしれません。%% 複数キーを使ったソートも可能です。デフォルトではソートキーは3つで、ヘッダにマークが表示されるのは最新のソートキーのみですが、クリックした順に保持されるようです。詳しくはドキュメントや[[Tableの内容をソート>http://syo.cocolog-nifty.com/freely/2006/08/table_616d.html]]などを参照してください。

----
RowSorter を直接指定しなくても、autoCreateRowSorter(true) とすると、JTable が自動的に RowSorter を作成して、ソートが出来るようになります。
#code{{
JTable table = new JTable(model);
table.setAutoCreateRowSorter(true);
}}

**参考リンク [#i6859196]
-[[How to Use Tables>http://java.sun.com/docs/books/tutorial/uiswing/components/table.html]]
-[[TableSorterでJTableをソート>Swing/TableSorter]]

**コメント [#dee0fa5e]
- DefaultRowSorter#setMaxSortKeys(int)で複数のキーを用いたソートも出来ているように思います(b86)。ただ、ヘッダー部分がわかりにくいですが。 -- [[syo]] &new{2006-08-03 (木) 11:12:55};
-- ご指摘ありがとうございます。なるほど、こちら([[Tableの内容をソート>http://syo.cocolog-nifty.com/freely/2006/08/table_616d.html]])を使えばうまくいきそうですね。 -- [[terai]] &new{2006-08-03 (木) 12:34:53};
- rendererがないので、基本的に数字は左揃え、文字列は右揃えで、中央揃えするにはどうすれば宜しいでしょうか? -- [[パンダ]] &new{2007-06-14 (木) 09:40:20};
--JTableは、Object、Number、Booleanクラスのデフォルトセルレンダラーを持っているため、モデル((DefaultTableModelはすべての列のクラスとして、Object.classを返す))が各列のクラスを正しく返すように、TableModel#getColumnClass(int)をオーバーライドしてやると、そのクラスのデフォルトセルレンダラーが使用され((列にセルレンダラーが割り当てられていない場合))、表示は数字右揃え、文字列左揃え((BooleanクラスだとJCheckBoxが表示される))になります。
#code{{
//ちょっとしたサンプルの場合は、以下のようにオーバーライドすると便利かも?
String[] columnNames = {"String", "Integer", "Boolean"};
Object[][] data = {
  {"AAA", 1, true},
  {"BBB", 2, false},
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
  @Override
  public Class<?> getColumnClass(int column) {
    return getValueAt(0, column).getClass();
  }
};
JTable table = new JTable(model);
}}
クラスのデフォルトセルレンダラーではなく、任意の列にセルレンダラーを割り当てて、例えば中揃えにしたい場合は、以下のように設定します。 -- [[terai]] &new{2007-06-14 (木) 13:19:36};
#code{{
DefaultTableCellRenderer r = new DefaultTableCellRenderer();
r.setHorizontalAlignment(JLabel.CENTER);
table.getColumnModel().getColumn(2).setCellRenderer(r);
}}

#comment