Saturday, January 08, 2011

A Paginated JList

If you have a large JList and don't want to scroll through it, it might be a better idea to "paginate" it i.e. display the list in "pages" of a few rows at a time and allow users to flip back and forth between them. To do this, I have written a Java Swing component called PaginatedList, which looks like this:

You pass in a JList and specify a page size (the page size is 10 in this example) and it returns a PaginatedList which you can add onto another JComponent as normal. The code is shown below:

import java.awt.BorderLayout;
import java.awt.GridLayout;
import java.awt.event.ActionEvent;

import javax.swing.AbstractAction;
import javax.swing.DefaultListModel;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JList;
import javax.swing.JPanel;
import javax.swing.ListModel;


/**
 * A paginated JList. Only displays a specific number of rows
 * and allows you to page back and forth through the list.
 * with the help of a toolbar.
 */
public class PaginatedList extends JPanel {

  private final int pageSize;
  private final JList list;
  private final ListModel model;
  private final int lastPageNum;
  private int currPageNum;
  private JLabel countLabel ;
  private JButton first, prev, next, last;

  /**
   * @param list the source list
   * @param pageSize the number of rows visible
   */
  public PaginatedList(JList list, int pageSize) {
      super();
      this.pageSize = pageSize;
      this.list = list;
      this.model = list.getModel();

      //work out how many pages there are
      this.lastPageNum = model.getSize() / pageSize +
                        (model.getSize() % pageSize != 0 ? 1 : 0);
      this.currPageNum = lastPageNum > 0 ? 1 : 0;

      setLayout(new BorderLayout());
      countLabel = new JLabel() ;
      add(countLabel, BorderLayout.NORTH);
      add(list, BorderLayout.CENTER);
      add(createControls(), BorderLayout.SOUTH);
      updatePage();
  }

  private JPanel createControls() {
      first = new JButton(new AbstractAction("<<") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = 1;
              updatePage();
          }
      });

      prev = new JButton(new AbstractAction("<") {
          public void actionPerformed(ActionEvent e) {
              if (--currPageNum <= 0)
                  currPageNum = 1;
              updatePage();
          }
      });

      next = new JButton(new AbstractAction(">") {
          public void actionPerformed(ActionEvent e) {
              if (++currPageNum > lastPageNum)
                  currPageNum = lastPageNum;
              updatePage();

          }
      });

      last = new JButton(new AbstractAction(">>") {
          public void actionPerformed(ActionEvent e) {
              currPageNum = lastPageNum;
              updatePage();
          }
      });

      JPanel bar = new JPanel(new GridLayout(1, 4));
      bar.add(first);
      bar.add(prev);
      bar.add(next);
      bar.add(last);
      return bar;
  }

  private void updatePage() {

      //replace the list's model with a new model containing
      //only the entries in the current page.
      if(model.getSize() != 0){
          final DefaultListModel page = new DefaultListModel();
          final int start = (currPageNum - 1) * pageSize;
          int end = start + pageSize;
          if (end >= model.getSize()) {
              end = model.getSize();
          }
          for (int i = start; i < end; i++) {
              page.addElement(model.getElementAt(i));
          }
          list.setModel(page);
      }

      //update the label
      countLabel.setText("Page " + currPageNum + "/" + lastPageNum);

      // update buttons
      final boolean canGoBack = currPageNum > 1;
      final boolean canGoFwd = currPageNum != lastPageNum;
      first.setEnabled(canGoBack);
      prev.setEnabled(canGoBack);
      next.setEnabled(canGoFwd);
      last.setEnabled(canGoFwd);
  }

  public static void main(String args[]) throws Exception {

      // create 100 elements of dummy data.
      String[] data = new String[101];
      for (int i = 0; i < data.length; i++) {
          data[i] = "Item "+ (i + 1);
      }

      // create a paginated list with page size 20
      PaginatedList list = new PaginatedList(new JList(data), 10);

      // add it to a frame
      JFrame f = new JFrame("Paginated List Demo");
      f.add(list);
      f.setSize(100, 100);
      f.pack();
      f.setVisible(true);
  }
}

1 comment:

  1. I needed something like this to save time on my coding. Thanks!

    ReplyDelete