概要

JTableのセルに設定した日付をRegexFilterなどでフィルタリングするテストを行います。

サンプルコード

ActionListener al = e -> {
  Object o = e.getSource();
  String txt = field.getText();
  if (r1.equals(o)) {
    sorter.setRowFilter(RowFilter.regexFilter(txt));
  } else if (r2.equals(o)) {
    sorter.setRowFilter(new RegexDateFilter(Pattern.compile(txt)));
  } else {
    sorter.setRowFilter(null);
  }
};

class RegexDateFilter extends RowFilter<TableModel, Integer> {
  private final Matcher matcher;
  protected RegexDateFilter(Pattern pattern) {
    super();
    this.matcher = pattern.matcher("");
  }

  @Override public boolean include(
      Entry<? extends TableModel, ? extends Integer> entry) {
    for (int i = entry.getValueCount() - 1; i >= 0; i--) {
      Object v = entry.getValue(i);
      if (v instanceof Date) {
        matcher.reset(DateFormat.getDateInstance().format(v));
      } else {
        matcher.reset(entry.getStringValue(i));
      }
      if (matcher.find()) {
        return true;
      }
    }
    return false;
  }
}
View in GitHub: Java, Kotlin

解説

  • null
    • フィルタをクリア
  • RowFilter.regexFilter
    • RowFilter.regexFilter(txt)を設定
    • 以下のようにRowFilter.regexFilterではDate#toString()メソッドが使用されるため、セルに表示中の文字列ではフィルタリングされない
      // @see javax/swing/RowFilter.java
      public static abstract class Entry<M, I> {
        // ...
        public String getStringValue(int index) {
          Object value = getValue(index);
          return (value == null) ? "" : value.toString();
        }
        // ...
      
    • 例: 12ではすべての行が非表示だがDecでは2行表示される
  • new RowFilter()
    • RowFilter<TableModel, Integer>を継承するフィルタを作成して設定
    • このフィルタでは以下のようにDateRendererが表示に使用しているデフォルトのDateFormatを使用してDateを文字列に変換してフィルタリングを行う
      // @see javax/swing/JTable.java
      static class DateRenderer extends DefaultTableCellRenderer.UIResource {
        public void setValue(Object value) {
          // ...
          DateFormat formatter = DateFormat.getDateInstance();
          setText((value == null) ? "" : formatter.format(value));
        }
      }
      

  • JDK 1.8.0以上の場合、toString()でロケールを無視するDateではなくLocalDateTimeを使用すればLocalDateTime#toString()ISO-8601形式の文字列を返すので面倒が少ない
LocalDateTime d = LocalDateTime.of(2002, 12, 31, 0, 0);
Object[][] data = {
  {date, d},
  {start, d.minus(2, ChronoUnit.DAYS)},
  {end, d.plus(7, ChronoUnit.DAYS)}
};
DefaultTableModel model = new DefaultTableModel(data, new String[] {"Date", "LocalDateTime"}) {
  @Override public Class<?> getColumnClass(int column) {
    return column == 0 ? Date.class : column == 1 ? LocalDateTime.class : Object.class;
  }
};

参考リンク

コメント