概要

JDK 1.5.0以前に、The Java™ TutorialにあったTableSorter.javaを使用して、JTableの行を降順、昇順、初期状態にソートします。

サンプルコード

//DefaultTableModel model = new DefaultTableModel();
TestModel model = new TestModel();
TableSorter sorter = new TableSorter(model);
JTable table = new JTable(sorter);
sorter.setTableHeader(table.getTableHeader());
view all

解説

The Java™ Tutorial版のTableSorterを使用して、JTableのソートで使用しているものと同じTableModelでソートしています。

TableSorterには、Ctrlキーを押しながらヘッダをクリックすると、そのカラムを第二キーとしてソートする機能もあります。

JDK 1.4.xWindows XPの環境で、ヘッダにカーソルを置いてもロールオーバーしない場合があるようです。上記のスクリーンショットはJDK 1.5.0_01で撮っています。


JDK 1.5.0Genericsの警告を出さないようにするには、TableSorter.javaに、以下のような修正を加えれば良いようです。

private static class ComparableComparator implements Comparator {
  @SuppressWarnings("unchecked")
  public int compare(Object o1, Object o2) {
    return ((Comparable) o1).compareTo(o2);
  }
}
public static final ComparableComparator COMPARABLE_COMAPRATOR
    = new ComparableComparator();
public static final ComparableComparator LEXICAL_COMPARATOR
    = new ComparableComparator() {
  @SuppressWarnings("unchecked")
  public int compare(Object o1, Object o2) {
    return o1.toString().compareTo(o2.toString());
  }
};
private TableModelListener tableModelListener;
private Map<Class, Comparator> columnComparators = new HashMap<>();
private List<Directive> sortingColumns = new ArrayList<>();

protected ComparableComparator getComparator(int column) {
  Class columnType = tableModel.getColumnClass(column);
  ComparableComparator comparator
      = (ComparableComparator) columnComparators.get(columnType);
    if (comparator != null) {
      return comparator;
    }
 private class Row implements Comparable<Row> {
  private int modelIndex;
  public Row(int index) {
    this.modelIndex = index;
  }
  public int compareTo(Row o) {
    int row1 = modelIndex;
    int row2 = o.modelIndex;
//......

LookAndFeelを動作中に切り替える場合は、sorter.setTableHeader(table.getTableHeader());で設定したJTableHeaderを新しいLookAndFeelを適用したものに入れ替えておかないと、NullPointerExceptionが発生します。

private final TableSorter sorter = new TableSorter(model);
private final JTable table = new JTable(sorter) {
  @Override public void updateUI() {
    sorter.setTableHeader(null);
    super.updateUI();
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        JTableHeader h = table.getTableHeader();
        sorter.setTableHeader(h);
        h.repaint();
      }
    });
  }
};

参考リンク

コメント

  • いつもお世話になっております。 jtableを下記のように初期化します。 -- Tiger
//DefaultTableModel model = new DefaultTableModel();
TestModel model = new TestModel();
TableSorter sorter = new TableSorter(model);
JTable table = new JTable(sorter);
sorter.setTableHeader(table.getTableHeader());
  • その後、ソートした状態で、一行ずつのデータを取り出した場合、 どうすればよろしいでしょうか?例えば、No.欄をソートして、下り順でNo.欄とName欄のデータをSystem.out.println(model.getValueAt(row, 1))したい場合、そのrowsorterに関連していると思います。 row=?かが分かりません。説明下手で、大変申し訳ございません。ご教示をください。よろしくお願い致します。 -- Tiger
    • こんにちは。多分、sorter.modelIndex(viewIndex);でいいと思います。 -- aterai
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import javax.swing.table.*;
public class SorterModelIndex {
  public JComponent makeUI() {
    String[] columnNames = {"String", "Integer", "Boolean"};
    Object[][] data = {
      {"aaa", 12, true}, {"bbb", 5, false},
      {"CCC", 92, true}, {"DDD", 0, false}
    };
    final DefaultTableModel model = new DefaultTableModel(data, columnNames) {
      @Override public Class<?> getColumnClass(int column) {
        return getValueAt(0, column).getClass();
      }
    };
    final TableSorter sorter = new TableSorter(model);
    final JTable table = new JTable(sorter);
    sorter.setTableHeader(table.getTableHeader());
    table.getSelectionModel().addListSelectionListener(new ListSelectionListener() {
      public void valueChanged(ListSelectionEvent e) {
        int viewIndex = table.getSelectedRow();
        if (!e.getValueIsAdjusting() && viewIndex >= 0) {
          Object o = model.getValueAt(sorter.modelIndex(viewIndex), 0);
          System.out.println(o);
        }
      }
    });

    JPanel p = new JPanel(new BorderLayout());
    p.add(new JScrollPane(table));
    return p;
  }
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      @Override public void run() {
        createAndShowGUI();
      }
    });
  }
  public static void createAndShowGUI() {
    JFrame f = new JFrame();
    f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    f.getContentPane().add(new SorterModelIndex().makeUI());
    f.setSize(320, 240);
    f.setLocationRelativeTo(null);
    f.setVisible(true);
  }
}
  • 早速のご回答、ありがとうございました。 選択された行の値を取り出すことができますが、今回表(jTable)の内容をCSVに書き出そうとしております。即ち選択した行がない場合、ソートをして(上り順CCCDDDaaabbb), jTable.getValueAt(sorter.modelIndex(i), j);i:行 j:列)、書き出した結果は(aaa, bbb, CCC, DDD)。即ちsorterしていなかったの状態で書き出されました。読みにくいかもしれませんが、ご教示ください。 宜しくお願い致します -- Tiger
    • JTableに表示されている見たまま(全選択、Ctrl+CでコピーしてTSV)の状態でということでしょうか。それならsorterは関係なく、以下のようにJTable#getValueAtメソッドを普通に使えばいいかもしれません(TableModel#getValueAtJTable#getValueAtの違いに注意)。 -- aterai
p.add(new JButton(new AbstractAction("test") {
  @Override public void actionPerformed(ActionEvent e) {
    for (int i = 0; i < table.getRowCount(); i++) {
      for (int j = 0; j < table.getColumnCount(); j++) {
        //Object o = table.getValueAt(i, table.convertColumnIndexToView(j));
        Object o = table.getValueAt(i, j);
        System.out.print(o+",");
      }
      System.out.print("\n");
    }
    System.out.println("----");
  }
}), BorderLayout.SOUTH);
  • ありがとうございました。ご指摘の通り、できました。 -- Tiger
  • いつもお世話になっております。JDK1.5を使っています。NameComment欄をソートするとき、No.欄はソートさせないで、固定のままできますか?ご教示をよろしくお願いいたします。 -- Tiger
    • こんにちは。以下のようなレンダラーを使って、表示をrow(View)にしてしまうのが簡単な気がします(Ctrl+CなどでコピーするとModelの値がコピーされたりしますが…)。 -- aterai
TableColumn col = table.getColumnModel().getColumn(0);
col.setCellRenderer(new DefaultTableCellRenderer() {
  @Override public Component getTableCellRendererComponent(
      JTable table, Object v, boolean isS, boolean hasF, int row, int col) {
    Component c = super.getTableCellRendererComponent(table, v, isS, hasF, row, col);
    if (c instanceof JLabel) ((JLabel) c).setText("" + row);
    return c;
  }
});
  • ご教示、ありがとうございました。思ったとおりの動きです。 -- Tiger