---
category: swing
folder: PageInputForPagination
title: JTableのPaginationとSwingWorkerでの逐次読み込み
tags: [JTable, RowFilter, SwingWorker, JButton]
author: aterai
pubdate: 2013-11-04T03:33:05+09:00
description: JTableでRowFilterを使ったPaginationとSwingWorkerでの逐次読み込みを行います。
image: https://lh5.googleusercontent.com/-1qIJd4HlwkQ/UnaN9fNNZtI/AAAAAAAAB5Y/JqssphQAq3Q/s800/PageInputForPagination.png
---
* 概要 [#summary]
`JTable`で`RowFilter`を使った`Pagination`と`SwingWorker`での逐次読み込みを行います。

#download(https://lh5.googleusercontent.com/-1qIJd4HlwkQ/UnaN9fNNZtI/AAAAAAAAB5Y/JqssphQAq3Q/s800/PageInputForPagination.png)

* サンプルコード [#sourcecode]
#code(link){{
worker = new SwingWorker<String, List<Object[]>>() {
  private int max = 2013;
  @Override public String doInBackground() {
    int current = 1;
    int c = max / itemsPerPage;
    int i = 0;
    while (i < c && !isCancelled()) {
      current = makeRowListAndPublish(current, itemsPerPage);
      i++;
    }
    int m = max % itemsPerPage;
    if (m > 0) {
      makeRowListAndPublish(current, m);
    }
    return "Done";
  }

  private int makeRowListAndPublish(int current, int size) {
    try {
      Thread.sleep(500); // dummy
      Thread.sleep(500);
    } catch (Exception ex) {
      ex.printStackTrace();
    }
    List<Object[]> result = new ArrayList<Object[]>(size);
    int j = current;
    while (j < current + size) {
      result.add(new Object[] {j, "Test: " + j, j % 2 == 0 ? "" : "comment..."});
      j++;
    }
    publish(result);
    return j;
  }

  @Override protected void process(List<List<Object[]>> chunks) {
    for (List<Object[]> list : chunks) {
      for (Object[] o : list) {
        model.addRow(o);
      }
    }
    int rowCount = model.getRowCount();
    maxPageIndex = (rowCount / itemsPerPage) + (rowCount % itemsPerPage == 0 ? 0 : 1);
    initFilterAndButton();
  }

  @Override public void done() {
    String text = null;
    if (isCancelled()) {
      text = "Cancelled";
    } else {
      try {
        text = get();
      } catch (Exception ex) {
        ex.printStackTrace();
        text = "Exception";
      }
    }
    table.setEnabled(true);
  }
};
worker.execute();

// ...
private static final int itemsPerPage = 100;
private int maxPageIndex;
private int currentPageIndex = 1;
private void initFilterAndButton() {
  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;
    }
  });
  first.setEnabled(currentPageIndex > 1);
  prev.setEnabled(currentPageIndex > 1);
  next.setEnabled(currentPageIndex < maxPageIndex);
  last.setEnabled(currentPageIndex < maxPageIndex);
  field.setText(Integer.toString(currentPageIndex));
  label.setText(String.format("/ %d", maxPageIndex));
}
}}

* 解説 [#explanation]
上記のサンプルでは、[[RowFilterでJTableのページ分割>Swing/TablePagination]]に以下の変更を追加しています。

- `JTextField`に数値を入力して指定ページにジャンプ可能
- `First(|<)`、`Prev(<)`、`Next(>)`、`Last(>|)`などのリンクに`JRadioButton`ではなく`JButton`を使用
- `SwingWorker`を使ってページ単位での逐次読み込み(最大ページの表示を更新)

----
- `SwingWorker`を使って`sqlite`から`JTable`にデータを読み込むテスト

#code{{
class LoadTask extends SwingWorker<String, List<Object[]>> {
  private final int max;
  private final int itemsPerPage;
  protected LoadTask(int max, int itemsPerPage) {
    super();
    this.max = max;
    this.itemsPerPage = itemsPerPage;
  }

  @Override public String doInBackground() {
    File file = new File(
      "C:/Users/.../AppData/Roaming/Mozilla/Firefox/Profiles/xx.default/places.sqlite");
    String db = "jdbc:sqlite:/" + file.getAbsolutePath();
    try (Connection conn = DriverManager.getConnection(db);
         Statement stat = conn.createStatement()) {
      int current = 1;
      int c = max / itemsPerPage;
      int i = 0;
      while (i < c && !isCancelled()) {
        try {
          Thread.sleep(500); // dummy
          Thread.sleep(500);
        } catch (InterruptedException ex) {
          // ex.printStackTrace();
          return "Interrupted";
        }
        current = load(stat, current, itemsPerPage);
        i++;
      }
      int surplus = max % itemsPerPage;
      if (surplus > 0) {
        load(stat, current, surplus);
      }
    } catch (SQLException ex) {
      // ex.printStackTrace();
      return "Error";
    }
    return "Done";
  }

  private int load(Statement stat, int current, int limit) throws SQLException {
    List<Object[]> result = new ArrayList<>(limit);
    String q = String.format(
        "select * from moz_bookmarks limit %d offset %d", limit, current - 1);
    ResultSet rs = stat.executeQuery(q);
    int i = current;
    while (rs.next() && !isCancelled()) {
      result.add(new Object[] {i, rs.getInt("id"), rs.getString("title")});
      i++;
    }
    publish(result);
    return current + result.size();
  }
}
}}

* 参考リンク [#reference]
- [[RowFilterでJTableのページ分割>Swing/TablePagination]]

* コメント [#comment]
#comment
#comment