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);
  }
});

以上でテーブル行のソートやフィルターができるようになりました。

ここまでお読みいただき、誠にありがとうございます。SNS 等でこの記事をシェアしていただけますと、大変励みになります。どうぞよろしくお願いします。

© 2024 Java 入門