TITLE:RowFilterでJTableのページ分割

Posted by aterai at 2007-11-05

RowFilterでJTableのページ分割

JDK 6 で導入されたRowFilterを使って、JTableの行をPagination風に分割して表示します。

  • &jnlp;
  • &jar;
  • &zip;
TablePagination.png

サンプルコード

private static int LR_PAGE_SIZE = 5;

private final String[] columnNames = {"Year", "String", "Comment"};
private final DefaultTableModel model = new DefaultTableModel(null, columnNames) {
  @Override public Class<?> getColumnClass(int column) {
    return (column==0)?Integer.class:Object.class;
  }
};
private final TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
private final Box box = Box.createHorizontalBox();
private void initLinkBox(final int itemsPerPage, final int currentPageIndex) {
  //assert currentPageIndex>0;
  sorter.setRowFilter(makeRowFilter(itemsPerPage, currentPageIndex-1));

  ArrayList<JRadioButton> l = new ArrayList<JRadioButton>();

  int startPageIndex = currentPageIndex-LR_PAGE_SIZE;
  if(startPageIndex<=0) startPageIndex = 1;

  int maxPageIndex = (model.getRowCount()/itemsPerPage)+1;
  int endPageIndex = currentPageIndex+LR_PAGE_SIZE-1;
  if(endPageIndex>maxPageIndex) endPageIndex = maxPageIndex;

  if(currentPageIndex>1)
    l.add(makePNRadioButton(itemsPerPage, currentPageIndex-1, "Prev"));
  for(int i=startPageIndex;i<=endPageIndex;i++) 
    l.add(makeRadioButton(itemsPerPage, currentPageIndex, i-1));
  if(currentPageIndex<maxPageIndex)
    l.add(makePNRadioButton(itemsPerPage, currentPageIndex+1, "Next"));

  box.removeAll();
  ButtonGroup bg = new ButtonGroup();
  box.add(Box.createHorizontalGlue());
  for(JRadioButton r:l) {
    box.add(r); bg.add(r);
  }
  box.add(Box.createHorizontalGlue());
  box.revalidate();
  box.repaint();
  l.clear();
}
private JRadioButton makeRadioButton(
      final int itemsPerPage, final int current, final int target) {
  JRadioButton radio = new JRadioButton(""+(target+1));
  radio.setForeground(Color.BLUE);
  radio.setUI(ui);
  if(target+1==current) {
    radio.setSelected(true);
    radio.setForeground(Color.BLACK);
  }
  radio.addActionListener(new ActionListener() {
    @Override public void actionPerformed(ActionEvent e) {
      initLinkBox(itemsPerPage, target+1);
    }
  });
  return radio;
}
private JRadioButton makePNRadioButton(
      final int itemsPerPage, final int target, String title) {
  JRadioButton radio = new JRadioButton(title);
  radio.setForeground(Color.BLUE);
  radio.setUI(ui);
  radio.addActionListener(new ActionListener() {
    @Override public void actionPerformed(ActionEvent e) {
      initLinkBox(itemsPerPage, target);
    }
  });
  return radio;
}
private RowFilter<TableModel,Integer> makeRowFilter(
      final int itemsPerPage, final int target) {
  return new RowFilter<TableModel,Integer>() {
    @Override
    public boolean include(Entry<? extends TableModel, ? extends Integer> entry) {
      int ei = entry.getIdentifier();
      return (target*itemsPerPage<=ei && ei<target*itemsPerPage+itemsPerPage);
    }
  };
}

解説

上記のサンプルは、検索サイトなどでよく使われている、PaginationをJTableで行っています。

ただし、ページ数が大量にある場合の処理や、前へ、次へなどの実装は無視して、

ある位置から一定の行数だけ表示するフィルタを予め作成し、これを上部のJRadioButton*1で切り替えています。

また、モデルのインデックス順でフィルタリングしているため、ソートを行っても表示される行の範囲内で変化します(参考:JTableのRowFilterを一旦解除してソート, TablePaginationTest.java)。

コメント

  • Prev、Next ボタンなどを追加して、Google風のPaginationを行うように変更しました。 -- aterai
  • ブログで指摘されていた恥ずかしいバグ(paintメソッドでコンポーネントの状態を変更し、無限ループ、CPU100%)を修正 -- aterai