概要

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

サンプルコード

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 TableRowSorter<TableModel> sorter = new TableRowSorter<TableModel>(model);
private Box box = Box.createHorizontalBox();

private void initLinkBox(final int itemsPerPage, final int currentPageIndex) {
  //assert currentPageIndex > 0;
  sorter.setRowFilter(new RowFilter<TableModel, Integer>() {
    @Override
    public boolean include(Entry<? extends TableModel, ? extends Integer> entry) {
      int ti = currentPageIndex - 1;
      int ei = entry.getIdentifier();
      return ti * itemsPerPage <= ei && ei < ti * itemsPerPage + itemsPerPage;
    }
  });

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

//#if 0 //BUG
  //int maxPageIndex = (model.getRowCount() / itemsPerPage) + 1;
//#else
  /* "maxPageIndex" gives one blank page if the module of the division is not zero.
   *   pointed out by erServi
   * e.g. rowCount=100, maxPageIndex=100
   */
  int rowCount = model.getRowCount();
  int v = rowCount % itemsPerPage == 0 ? 0 : 1;
  int maxPageIndex = rowCount / itemsPerPage + v;
//#endif
  int endPageIndex = currentPageIndex + LR_PAGE_SIZE - 1;
  if (endPageIndex > maxPageIndex) {
    endPageIndex = maxPageIndex;
  }

  box.removeAll();
  if (startPageIndex >= endPageIndex) {
    //if I only have one page, Y don't want to see pagination buttons
    //suggested by erServi
    return;
  }

  ButtonGroup bg = new ButtonGroup();
  JRadioButton f = makePrevNextRadioButton(
      itemsPerPage, 1, "|<", currentPageIndex > 1);
  box.add(f);
  bg.add(f);
  JRadioButton p = makePrevNextRadioButton(
      itemsPerPage, currentPageIndex - 1, "<", currentPageIndex > 1);
  box.add(p);
  bg.add(p);
  box.add(Box.createHorizontalGlue());
  for (int i = startPageIndex; i <= endPageIndex; i++) {
    JRadioButton c = makeRadioButton(itemsPerPage, currentPageIndex, i);
    box.add(c);
    bg.add(c);
  }
  box.add(Box.createHorizontalGlue());
  JRadioButton n = makePrevNextRadioButton(
      itemsPerPage, currentPageIndex + 1, ">", currentPageIndex < maxPageIndex);
  box.add(n);
  bg.add(n);
  JRadioButton l = makePrevNextRadioButton(
      itemsPerPage, maxPageIndex, ">|", currentPageIndex < maxPageIndex);
  box.add(l);
  bg.add(l);
  box.revalidate();
  box.repaint();
}
view all

解説

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

ある位置から一定の行数だけ表示するフィルタを予め作成し、これを上部のJRadioButton(BasicRadioButtonUIを継承して見た目だけリンク風に変更)で切り替えています。

また、モデルのインデックス順でフィルタリングしているため、ソートを行っても表示される行の範囲内で変化します。

参考リンク

コメント

  • PrevNextボタンなどを追加して、Google風のPaginationを行うように変更しました。 -- aterai
  • ブログで指摘されていた恥ずかしいバグ(paintメソッドでコンポーネントの状態を変更し、無限ループ、CPU100%)を修正 -- aterai
  • blogspotで、無駄な空白ページができるバグを指摘してもらったので、こちらも修正しました。 -- aterai
  • 先頭と最後にジャンプするボタンを追加。 -- aterai