JTable でデータフィルターを実装する方法
この記事では JTable のデータフィルター機能を実装します。
出来上がりは次のような画面になります。フィルターの文字を入力すると、中央のカラムの値で行がフィルターされて表示されています。
フィルターの実装はローフィルターとローソーターの組み合わせで
さて、フィルターはどのように実装すればよいでしょうか。
これまでの記事で、セルを描くのは「テーブルセルレンダラー」、 セルの編集を行うのは「テーブルセルエディター」、 セルのソートは「テーブルローソーター」であることをみてきました。
「フィルターを行うオブジェクトは『テーブルローフィルター』オブジェクトがあるのかな?」と、予想できますが、その通りです。 ただし、ローフィルターを単体で使うのではなくてローソーターと組み合わせて使います。
フィルター条件入力のパネルを追加
まずは準備として、フィルター条件を入力するパネルを用意しましょう。
今回は JPanel にテキストフィールド JTextField とラベル JLabel を追加して、 それをフレームの上部に設置しました。
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(350, 150);
// フィルターパネル
JPanel filterPanel = new JPanel();
BoxLayout boxLayout = new BoxLayout(filterPanel, BoxLayout.X_AXIS);
filterPanel.setLayout(boxLayout);
JLabel filterLabel = new JLabel("Filter:");
filterPanel.add(filterLabel);
filterLabel.setLabelFor(filterText);
filterPanel.add(filterText);
add(filterPanel, BorderLayout.NORTH);
...
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
この辺は適当に変更してください。
ローフィルターの実装
フィルター機能はテーブルローソーターオブジェクトに、ローフィルターを設定することで実現します。
上記で作ったテキストフィールドの変更イベントにて、ローフィルターを差し替えます。
コード全体は次のようになります。(足りない部分は前の記事「JTable での単純なソート(並べ替え)」等をみてください)
package com.keicode.java.testapp;
import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import javax.swing.JTextField;
import javax.swing.RowFilter;
import javax.swing.SwingUtilities;
import javax.swing.table.TableColumn;
import javax.swing.table.TableRowSorter;
@SuppressWarnings("serial")
public class TableTest20 extends JFrame {
final JTable table = new JTable();
final MyTableModel3 tableModel = new MyTableModel3();
final TableRowSorter<MyTableModel3> sorter = new TableRowSorter<MyTableModel3>(tableModel);
final JTextField filterText = new JTextField();
public TableTest20() {
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
setLayout(new BorderLayout());
setSize(350, 150);
// フィルターパネル
JPanel filterPanel = new JPanel();
BoxLayout boxLayout = new BoxLayout(filterPanel, BoxLayout.X_AXIS);
filterPanel.setLayout(boxLayout);
JLabel filterLabel = new JLabel("Filter:");
filterPanel.add(filterLabel);
filterText.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent e) {
RowFilter<MyTableModel3, Object> filter = null;
try {
filter = RowFilter.regexFilter(filterText.getText(), 1);
}
catch(Exception ex) {
}
sorter.setRowFilter(filter);
}
});
filterLabel.setLabelFor(filterText);
filterPanel.add(filterText);
add(filterPanel, BorderLayout.NORTH);
// テーブルの設定
table.setRowSorter(sorter);
table.setModel(tableModel);
TableColumn col = table.getColumnModel().getColumn(0);
col.setCellRenderer(new MyTableCellRenderer());
col.setCellEditor(new MyCellEditor());
JScrollPane scrollPane = new JScrollPane(table);
add(scrollPane, BorderLayout.CENTER);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
TableTest20 app = new TableTest20();
app.setVisible(true);
}
});
}
}
テキストフィールドのアクションリスナーの actionPerformed にて、フィルターを作成して、ソーターオブジェクトにセットしています。
RowFilter.regexFilter メソッドの第2引数がカラムのインデックスです。
ちなみに、上記のコードではフィルターとする文字を入力して、Enter キーを押したタイミングでフィルターが実行されます。 フィルターとする文字を入力する度にフィルターを適用するには、次のようにテキストフィールドのドキュメントにリスナーを設定します。
filterText.getDocument().addDocumentListener(new DocumentListener() {
@Override
public void insertUpdate(DocumentEvent e) {
handleUpdate();
}
@Override
public void removeUpdate(DocumentEvent e) {
handleUpdate();
}
@Override
public void changedUpdate(DocumentEvent e) {
handleUpdate();
}
void handleUpdate() {
RowFilter<MyTableModel3, Object> filter = null;
try {
filter = RowFilter.regexFilter(filterText.getText(), 1);
}
catch(Exception ex) {
}
sorter.setRowFilter(filter);
}
});
以上でテーブル行のソートやフィルターができるようになりました。