---
category: swing
folder: TableSorter
title: TableSorterでJTableをソート
tags: [JTable, TableSorter]
author: aterai
pubdate: 2005-02-28T18:44:05+09:00
description: JDK 1.5.0以前に、The Java™ Tutorialに存在したTableSorter.javaを使用して、JTableの行を降順、昇順、初期状態にソートします。
image: https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTUp0MLx6I/AAAAAAAAAmY/omjw4LoJbbc/s800/TableSorter.png
---
* Summary [#summary]
`JDK 1.5.0`以前に、`The Java™ Tutorial`に存在した`TableSorter.java`を使用して、`JTable`の行を降順、昇順、初期状態にソートします。
#download(https://lh3.googleusercontent.com/_9Z4BYR88imo/TQTUp0MLx6I/AAAAAAAAAmY/omjw4LoJbbc/s800/TableSorter.png)
* Source Code Examples [#sourcecode]
#code(link){{
// DefaultTableModel model = new DefaultTableModel();
TestModel model = new TestModel();
TableSorter sorter = new TableSorter(model);
JTable table = new JTable(sorter);
sorter.setTableHeader(table.getTableHeader());
}}
* Description [#explanation]
* Description [#description]
`The Java™ Tutorial`版の`TableSorter`を使用して、[[JTableのソート>Swing/SortableTable]]で使用しているものと同じ`TableModel`をソートしています。
- `TableSorter`にはKBD{Ctrl}キーを押しながらヘッダをクリックすると、そのカラムを第`2`キー、第`3`キーとしてソートする機能もある
- `JDK 1.5.0`で`Generics`の警告を出さないようにするには`TableSorter.java`に以下のような修正が必要
#code{{
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`が発生する
#code{{
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();
}
});
}
};
}}
----
- `JDK 1.6.0`から`JTable`には標準でソート機能が追加された
-- [http://www.oracle.com/technetwork/articles/javase/index-135205.html#1 Table Sorting and Filtering - New and Updated Desktop Features in Java SE 6, Part 2]
-- [[TableRowSorterでJTableのソート>Swing/TableRowSorter]]
* Reference [#reference]
- [https://docs.oracle.com/javase/tutorial/uiswing/components/table.html#sorting Sorting and Otherwise Manipulating Data - How to Use Tables (The Java™ Tutorials > Creating a GUI with JFC/Swing > Using Swing Components)]
- [https://docs.oracle.com/javase/tutorial/uiswing/components/table.html How to Use Tables]
- [https://community.oracle.com/thread/1185784 Generics - Simple method but hard with generics: compareTo()]
- [https://docs.oracle.com/javase/tutorial/uiswing/examples/components/TableSorterDemoProject/src/components/TableSorter.java TableSorter.java]
* Comment [#comment]
#comment
- いつもお世話になっております。 `jtable`を下記のように初期化します。 -- &user(Tiger); &new{2010-08-05 (木) 06:07:47};
#code{{
// 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))`したい場合、その`row`は`sorter`に関連していると思います。 `row=?`かが分かりません。説明下手で、大変申し訳ございません。ご教示をください。よろしくお願い致します。 -- &user(Tiger); &new{2010-08-05 (木) 06:07:47};
-- こんにちは。多分、`sorter.modelIndex(viewIndex);`でいいと思います。 -- &user(aterai); &new{2010-08-05 (木) 13:17:51};
#code{{
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}
};
DefaultTableModel model = new DefaultTableModel(data, columnNames) {
@Override public Class<?> getColumnClass(int column) {
return getValueAt(0, column).getClass();
}
};
TableSorter sorter = new TableSorter(model);
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`に書き出そうとしております。即ち選択した行がない場合、ソートをして(上り順`CCC`、`DDD`、`aaa`、`bbb`), `jTable.getValueAt(sorter.modelIndex(i), j);`(`i`:行 `j`:列)、書き出した結果は(`aaa`, `bbb`, `CCC`, `DDD`)。即ち`sorter`していなかったの状態で書き出されました。読みにくいかもしれませんが、ご教示ください。 宜しくお願い致します -- &user(Tiger); &new{2010-08-05 (木) 15:42:51};
-- `JTable`に表示されている見たまま(全選択、KBD{Ctrl+C}でコピーして`TSV`)の状態でということでしょうか。それなら`sorter`は関係なく、以下のように`JTable#getValueAt`メソッドを普通に使えばいいかもしれません(`TableModel#getValueAt`と`JTable#getValueAt`の違いに注意)。 -- &user(aterai); &new{2010-08-05 (木) 17:54:10};
#code{{
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);
}}
- ありがとうございました。ご指摘の通り、できました。 -- &user(Tiger); &new{2010-08-05 (木) 18:08:42};
- いつもお世話になっております。`JDK1.5`を使っています。`Name`と`Comment`欄をソートするとき、`No.`欄はソートさせないで、固定のままできますか?ご教示をよろしくお願いいたします。 -- &user(Tiger); &new{2010-09-10 (金) 12:41:32};
-- こんにちは。以下のようなレンダラーを使って、表示を`row(View)`にしてしまうのが簡単な気がします(KBD{Ctrl+C}などでコピーすると`Model`の値がコピーされたりしますが…)。 -- &user(aterai); &new{2010-09-10 (金) 14:45:58};
#code{{
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;
}
});
}}
- ご教示、ありがとうございました。思ったとおりの動きです。 -- &user(Tiger); &new{2010-09-10 (金) 16:32:27};
#comment