TITLE:TableRowSorterでJTableのソート

TableRowSorterでJTableのソート

編集者:Terai Atsuhiro~

作成日:2007-02-12
更新日:2022-10-14 (金) 13:42:44
  • category: swing folder: TableRowSorter title: TableRowSorterでJTableのソート tags: [JTable, TableRowSorter, JTableHeader] author: aterai pubdate: 2007-02-12T18:36:03+09:00 description: JDK 6で導入されたTableRowSorterを利用してJTableの行を降順、昇順にソートします。 image: https://lh4.googleusercontent.com/_9Z4BYR88imo/TQTUnbg2jyI/AAAAAAAAAmU/-7yjlGSjBmo/s800/TableRowSorter.png

概要

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

概要

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

#screenshot

サンプルコード

#spanend
#spandel
TestModel model = new TestModel();
#spanend
#spanadd
* サンプルコード [#sourcecode]
#spanend
#spanadd
#code(link){{
#spanend
#spanadd
TableModel model = makeTestTableModel();
#spanend
JTable table = new JTable(model);
RowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
table.setRowSorter(sorter);
  • &jnlp;
  • &jar;
  • &zip;

解説

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

解説

JDK 6ではJTableTableRowSorterを設定することでカラムヘッダのクリックによる行ソートが行えます。 TableRowSorterのデフォルトでは、ヘッダクリックで(降順、昇順)とソートが切り替わり、TableSorterのように(降順、昇順、初期状態)ではなくなっています。上記のサンプルでは、下のボタンをクリックすると、DefaultRowSorter#setSortKeys(List)にnullを代入することで初期状態に戻るようにしていますが、SwingLabsのJXTableみたいにShift+ヘッダクリックで初期状態に戻るようにしてもいいかもしれません(参考:TableRowSorterのSortKeysをクリアする)。
  • 以下のようにJTable#autoCreateRowSorter(true)メソッドを使用した場合も、JTableが自動的にRowSorterを作成してソートが可能になる
    #spanend
    #spanadd
    JTable table = new JTable(model);
    #spanend
    #spanadd
    table.setAutoCreateRowSorter(true);
    #spanend
    #spanadd
    
また、DefaultRowSorter#setSortable(int, boolean)でソートしたくないカラムを以前より簡単に指定できます(参考:JTableHeaderのカラムを選択不可にする)。
  • -
  • TableRowSorterのデフォルトではヘッダクリックで(降順、昇順)とソートが切り替わり、TableSorter.javaのように(降順、昇順、初期状態)ではなくなっている
    • このページのサンプルではBorderLayout.SOUTHに配置したボタンをクリックするとDefaultRowSorter#setSortKeys(List)nullを代入することで初期状態に戻るよう設定している
  • SwingLabsJXTableのように「Shift+ヘッダクリック」で初期状態に戻す
  • TableSorter.javaのようにヘッダクリックで降順、昇順、初期状態とループ
第二キーを使ったソートはTableRowSorter版では出来ない?ようなので、TableSorter.javaを使う場合もまだあるかもしれません。 複数キーを使ったソートも可能です。デフォルトではソートキーは3つで、ヘッダにマークが表示されるのは最新のソートキーのみですが、クリックした順に保持されるようです。詳しくはドキュメントやTableの内容をソートなどを参照してください。
  • -

参考リンク

  • How to Use Tables
  • TableSorterでJTableをソート
    • -
  • TableModelに要素を追加した後でtable.setRowSorter(sorter);とすると、IndexOutOfBoundsException: Invalid rangeがモデルへの追加、削除、編集中に別の行クリックなどで発生する
    • 以下のサンプルの場合model.fireTableDataChanged()メソッドをtable.setRowSorter(sorter)の後で呼び出すと回避可能

コメント

  • DefaultRowSorter#setMaxSortKeys(int)で複数のキーを用いたソートも出来ているように思います(b86)。ただ、ヘッダー部分がわかりにくいですが。 -- syo
    • ご指摘ありがとうございます。なるほど、こちら(Tableの内容をソート)を使えばうまくいきそうですね。 -- terai
  • rendererがないので、基本的に数字は左揃え、文字列は右揃えで、中央揃えするにはどうすれば宜しいでしょうか? -- パンダ
    • JTableは、Object、Number、Booleanクラスのデフォルトセルレンダラーを持っているため、モデル*1が各列のクラスを正しく返すように、TableModel#getColumnClass(int)をオーバーライドしてやると、そのクラスのデフォルトセルレンダラーが使用され*2、表示は数字右揃え、文字列左揃え*3になります。
      #spandel
      //ちょっとしたサンプルの場合は、以下のようにオーバーライドする方法をよく見かけます。
      #spanend
      #spandel
      String[] columnNames = {"String", "Integer", "Boolean"};
      #spanend
      #spandel
      Object[][] data = {
      #spanend
        {"AAA", new Integer(1), new Boolean(true)},
        {"BBB", new Integer(2), new Boolean(false)},
      #spandel
      };
      #spanend
      #spandel
      DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      #spanend
        @Override
        public Class getColumnClass(int column) {
          return getValueAt(0, column).getClass();
      #spanadd
      import java.awt.*;
      #spanend
      #spanadd
      import java.awt.event.*;
      #spanend
      #spanadd
      import javax.swing.*;
      #spanend
      #spanadd
      import javax.swing.table.*;
      #spanend
      #spanadd
      
      #spanend
      #spanadd
      public class RowSorterTest extends JPanel {
      #spanend
        public RowSorterTest() {
          super(new BorderLayout());
          final DefaultTableModel model = new DefaultTableModel(null, new String[] {"A", "B", "C"});
          JTable table = new JTable(model);
          TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
          // table.setRowSorter(sorter); // OK
          model.addRow(new String[] {"aa", "bb", "cc"});
          model.addRow(new String[] {"dd", "ee", "ff"});
          table.setRowSorter(sorter); // IndexOutOfBoundsException: Invalid range
          // model.fireTableDataChanged(); // <----
          add(new JButton(new AbstractAction("model.addRow(...); -> IndexOutOfBoundsException") {
            @Override public void actionPerformed(ActionEvent e) {
              model.addRow(new String[] {"gg", "hh", "ii"});
            }
          }), BorderLayout.SOUTH);
          add(new JScrollPane(table));
        }
      #spandel
      };
      #spanend
      #spandel
      JTable table = new JTable(model);
      #spanend
      #spanadd
      
      #spanend
        public static void main(String[] args) {
          EventQueue.invokeLater(new Runnable() {
            @Override public void run() { createAndShowGUI(); }
          });
        }
      #spanadd
      
      #spanend
        public static void createAndShowGUI() {
          JFrame frame = new JFrame("Test");
          frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
          frame.getContentPane().add(new RowSorterTest());
          frame.setSize(320, 240);
          frame.setLocationRelativeTo(null);
          frame.setVisible(true);
        }
      #spanadd
      }
      #spanend
      
      クラスのデフォルトセルレンダラーではなく、任意の列にセルレンダラーを割り当てて、例えば中揃えにしたい場合は、以下のように設定します。 -- terai
      #spanend
      #spandel
      DefaultTableCellRenderer r = new DefaultTableCellRenderer();
      #spanend
      #spandel
      r.setHorizontalAlignment(JLabel.CENTER);
      #spanend
      #spandel
      table.getColumnModel().getColumn(2).setCellRenderer(r);
      #spanend
      #spandel
      
  • RowSorter (Java Platform SE 8)

    RowSorterの具象実装は、TableModelListModelなどのモデルを参照する必要があります。JTableJListなどのビュークラスも、モデルを参照します。順序の依存性を回避するため、RowSorter実装がモデル上にリスナーをインストールしないようにしてください。モデルが変更されると、ビュークラスがRowSorterを呼び出します。例えば、TableModel JTable で行が更新された場合、rowsUpdatedが呼び出されます。モデルが変更されると、ビューは、modelStructureChangedallRowsChangedrowsInsertedrowsDeletedrowsUpdatedのいずれかのメソッドを呼び出します。

参考リンク

コメント