• 追加された行はこの色です。
  • 削除された行はこの色です。
TITLE:RowFilterでJTableのページ分割
#navi(../)
*RowFilterでJTableのページ分割 [#sff7ad1c]
>編集者:[[Terai Atsuhiro>terai]]~
作成日:2007-11-05~
更新日:&lastmod;
---
category: swing
folder: TablePagination
title: RowFilterでJTableのページ分割
tags: [JTable, RowFilter, JRadioButton]
author: aterai
pubdate: 2007-11-05T14:35:32+09:00
description: JDK 6で導入されたRowFilterを使って、JTableの行をPagination風に分割して表示します。
image: https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTUiUh8yiI/AAAAAAAAAmM/eY1zd24d0ac/s800/TablePagination.png
hreflang:
    href: https://java-swing-tips.blogspot.com/2008/03/jtable-pagination-example-using.html
    lang: en
---
* 概要 [#summary]
`JDK 6`で導入された`RowFilter`を使って、`JTable`の行を`Pagination`風に分割して表示します。

#contents
#download(https://lh6.googleusercontent.com/_9Z4BYR88imo/TQTUiUh8yiI/AAAAAAAAAmM/eY1zd24d0ac/s800/TablePagination.png)

**概要 [#p2b85520]
JDK 6 で導入されたRowFilterを使って、JTableの行をPagination風に分割して表示します。
* サンプルコード [#sourcecode]
#code(link){{
private static int LR_PAGE_SIZE = 5;

#screenshot
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();

**サンプルコード [#l576bdcf]
#code{{
void initLinkBox(Box box, TestModel m, final TableRowSorter<TestModel> sorter,
                 final int size, final int step) {
  m.setRowCount(0);
  for(int i=0;i<size;i++) {
    m.addTest(new Test("Name"+i, (i%2==0)?"":"comment..."));
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();
  final ButtonGroup bg = new ButtonGroup();
  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());
  box.setBorder(BorderFactory.createEmptyBorder(0,0,5,0));
  int page = 0;
  for(int i=0;i<size;i+=step) {
    page++;
    final int index = i;
    final JRadioButton rb = new JRadioButton(""+page);
    final RowFilter<TestModel,Integer> filter = new RowFilter<TestModel,Integer>() {
      @Override
      public boolean include(Entry<? extends TestModel, ? extends Integer> entry) {
        int ei = entry.getIdentifier();
        return (index<=ei && ei<index+step);
      }
    };
    rb.setForeground(Color.BLUE);
    rb.setUI(ui);
    rb.setAction(new AbstractAction(""+page) {
      @Override
      public void actionPerformed(ActionEvent e) {
        sorter.setRowFilter(filter);
      }
    });
    box.add(rb);
    bg.add(rb);
    if(i==0) {
      rb.setSelected(true);
      sorter.setRowFilter(filter);
    }
  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();
}
}}
-&jnlp;
-&jar;
-&zip;

**解説 [#uc3887af]
上記のサンプルは、検索サイトなどでよく使われている、PaginationをJTableで行っています。
* 解説 [#explanation]
上記のサンプルは、検索サイトなどでよく使われている`Pagination`風の処理を`JTable`で行っています。

ただし、ページ数が大量にある場合の処理や、前へ、次へなどの実装は無視して、ある位置から一定の行数だけ表示するフィルタを予め作成し、これを上部のJRadioButton((BasicRadioButtonUIを継承して見た目だけリンク風になるよう変更している))で切り替えるだけになっています。
- ある位置から一定の行数だけ表示するフィルタを予め作成し、これを上部の`JRadioButton`で切り替え
-- この`JRadioButton`は`BasicRadioButtonUI`を継承して見た目だけリンク風に変更している
- モデルのインデックス順でフィルタリングしているため、ソートを行っても表示される行の範囲内で変化する

また、モデルのインデックス順でフィルタリングしているため、ソートを行っても、表示される行の順番が変化するだけになります。
- 参考: [[JTableのRowFilterを一旦解除してソート>Swing/ResetRowFilter]]
-- [https://ateraimemo.com/data/swing/TablePaginationTest.java TablePaginationTest.java]

//**参考リンク
**コメント [#n7c8e61e]
* 参考リンク [#reference]
- [[JTableのPaginationとSwingWorkerでの逐次読み込み>Swing/PageInputForPagination]]

* コメント [#comment]
#comment
- `Prev`、`Next`ボタンなどを追加して、Google風の`Pagination`を行うように変更しました。 -- &user(aterai); &new{2008-03-26 (水) 20:28:31};
- ブログで指摘されていた恥ずかしいバグ(`paint`メソッドでコンポーネントの状態を変更し、無限ループ、`CPU100%`)を修正 -- &user(aterai); &new{2008-09-07 (日) 00:08:50};
- [https://java-swing-tips.blogspot.com/2008/03/jtable-pagination-example-using.html blogspot]で、無駄な空白ページができるバグを指摘してもらったので、こちらも修正しました。 -- &user(aterai); &new{2011-08-15 (月) 15:54:08};
- 先頭と最後にジャンプするボタンを追加。 -- &user(aterai); &new{2013-11-01 (金) 16:09:21};

#comment