How to implement pagination in Java

The process of pagination is to divide a big dataset into smaller, more manageable pieces, or pages. Most of the time, each page has a limited number of things or records on it. Users can move from page to page to find the information they want, which makes data retrieval and display more efficient.

Pagination
Pagination
Pagination with disabled and active states
Pagination with disabled and active states

Pagination techniques

There are various pagination techniques, but two commonly used approaches are:

  1. Offset-based pagination

  2. Keyset pagination

Offset-based pagination

Offset-based pagination relies on providing the page number and the number of items per page (page size). By using the offset and limit values, the database query retrieves a specific part of the data. This technique is suitable for datasets that don't change frequently.

Implementation

Here is a simple example of offset-based pagination in Java Swing.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Main extends JFrame {
    private static final int PAGE_SIZE = 5;
    private static final String[] ITEMS = {
            "Item 1", "Item 2", "Item 3", "Item 4", "Item 5",
            "Item 6", "Item 7", "Item 8", "Item 9", "Item 10",
            "Item 11", "Item 12", "Item 13", "Item 14", "Item 15",
            "Item 16", "Item 17", "Item 18", "Item 19", "Item 20", "Item 21", "Item 22", "Item 23"
    };

    private JPanel mainPanel;
    private JLabel currentPageLabel;
    private JButton previousButton;
    private JButton nextButton;
    private JTextArea itemsTextArea;

    private int currentPage = 1;

    public Main() {
        setTitle("Pagination Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setPreferredSize(new Dimension(300, 200));

        mainPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
        currentPageLabel = new JLabel();
        previousButton = new JButton("Previous");
        nextButton = new JButton("Next");
        itemsTextArea = new JTextArea(10, 20);

        previousButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                if (currentPage > 1) {
                    currentPage--;
                    updatePage();
                }
            }
        });

        nextButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                int totalPages = (int) Math.ceil((double) ITEMS.length / PAGE_SIZE);
                if (currentPage < totalPages) {
                    currentPage++;
                    updatePage();
                }
            }
        });

        mainPanel.add(previousButton);
        mainPanel.add(currentPageLabel);
        mainPanel.add(nextButton);
        mainPanel.add(new JScrollPane(itemsTextArea));

        add(mainPanel);

        pack();
        setLocationRelativeTo(null);
        updatePage();
    }

    private void updatePage() {
        currentPageLabel.setText("Page " + currentPage);

        // Calculate the starting and ending indexes for the current page
        int startIndex = (currentPage - 1) * PAGE_SIZE;
        int endIndex = Math.min(startIndex + PAGE_SIZE, ITEMS.length);

        // Clear the previous items and add the new ones
        itemsTextArea.setText("");
        for (int i = startIndex; i < endIndex; i++) {
            itemsTextArea.append(ITEMS[i] + "\n");
        }

        // Update the GUI
        revalidate();
        repaint();
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                new Main().setVisible(true);
            }
        });
    }
}

Explanation

  • Line 21: The currentPage variable represents the current page number and is initially set to 1.

  • Lines 23–65: The constructor of the Main class. It sets up the GUI components, adds event listeners to the buttons, and initializes the window.

  • Lines 24–26: The window title, default close operation, and preferred size of the window are set.

  • Line 28: The mainPanel is created with a FlowLayout manager, which arranges the components in a single row with a specified gap.

  • Lines 29–32: The currentPageLabel, previousButton, nextButton, and itemsTextArea components are initialized.

  • Lines 34–53: Action listeners are added to the previous and next buttons using anonymous inner classes. These listeners handle the button clicks and update the current page accordingly.

  • Lines 6264: The frame is packed, centered on the screen, and the updatePage method is called to display the initial page.

  • Lines 67–83: The updatePage method updates the GUI based on the current page. It sets the current page label, calculates the starting and ending indexes for the page, clears the previous items, and adds new items to the text area. Finally, it updates the GUI by calling revalidate and repaint.

Keyset pagination

Keyset pagination uses the values of a unique key (like an ID or timestamp) to figure out which pages come next and which ones come before. It gets rid of the need for offsets and improves speed when working with big datasets or with data that changes often.

Implementation

Here is a simple example of keyset-based pagination in Java Swing.

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.util.*;

public class Main extends JFrame {
    private TreeSet<String> data;

    private JLabel pageLabel;
    private JButton prevButton;
    private JButton nextButton;

    private JTextArea outputTextArea;

    private static final int PAGE_SIZE = 10;
    private NavigableSet<String> currentPage;
    private ListIterator<String> currentPageIterator;

    public Main() {
        // Initialize your data set (sorted TreeSet in this example)
        data = new TreeSet<>();
        data.add("Apple");
        data.add("Banana");
        data.add("Cherry");
        data.add("Durian");
        data.add("Grapes");
        data.add("Kiwi");
        data.add("Mango");
        data.add("Orange");
        data.add("Peach");
        data.add("Pear");
        data.add("Apple2");
        data.add("Banana2");
        data.add("Cherry2");
        data.add("Durian2");
        data.add("Grapes2");
        data.add("Kiwi2");

        // Set up the UI
        setTitle("Keyset Pagination Example");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        JPanel paginationPanel = new JPanel();
        prevButton = new JButton("Previous");
        nextButton = new JButton("Next");
        pageLabel = new JLabel("Page: 1");

        outputTextArea = new JTextArea();
        JScrollPane scrollPane = new JScrollPane(outputTextArea);
        add(scrollPane, BorderLayout.CENTER);

        paginationPanel.add(prevButton);
        paginationPanel.add(pageLabel);
        paginationPanel.add(nextButton);

        add(paginationPanel, BorderLayout.SOUTH);

        prevButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                showPreviousPage();
            }
        });

        nextButton.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {
                showNextPage();
            }
        });

        // Display the initial page
        showPage(1);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    private void showPage(int page) {
        int startIndex = (page - 1) * PAGE_SIZE;
        currentPage = data.stream()
                .skip(startIndex)
                .limit(PAGE_SIZE)
                .collect(TreeSet::new, TreeSet::add, TreeSet::addAll);

        currentPageIterator = new ArrayList<>(currentPage).listIterator();
        updateUI(page);
    }

    private void showNextPage() {
        if (currentPageIterator.hasNext()) {
            currentPageIterator.next();
        }
        if (!currentPageIterator.hasNext()) {
            int currentPageNumber = Integer.parseInt(pageLabel.getText().substring(6));
            showPage(currentPageNumber + 1);
        } else {
            updateUI(Integer.parseInt(pageLabel.getText().substring(6)));
        }
    }

    private void showPreviousPage() {
        if (currentPageIterator.hasPrevious()) {
            currentPageIterator.previous();
        }
        if (!currentPageIterator.hasPrevious()) {
            int currentPageNumber = Integer.parseInt(pageLabel.getText().substring(6));
            showPage(currentPageNumber - 1);
        } else {
            updateUI(Integer.parseInt(pageLabel.getText().substring(6)));
        }
    }

    private void updateUI(int page) {
        pageLabel.setText("Page: " + page);

        // Update your UI with the current page's data
        outputTextArea.setText("Items on Page " + page + ":\n");
        while (currentPageIterator.hasNext()) {
            outputTextArea.append(currentPageIterator.next() + "\n");
        }
        outputTextArea.append("------------------------------------\n");
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new Main();
            }
        });
    }
}

Explanation

  • Lines 8–18: The class members are defined, including a TreeSet called data to store the data set, and GUI components such as JLabel, JButton, and JTextArea for displaying the pagination UI and output.

  • Lines 20–38: The constructor for the Main class is defined. Inside the constructor, the data set is initialized with sample data.

  • Lines 60–72: Action listeners are added to the "Previous" and "Next" buttons to handle the corresponding button clicks.

  • Lines 75: The showPage method is called to display the initial page.

  • Lines 82–91: The showPage method is defined. It takes a page number as input and calculates the start index for the current page. It then creates a TreeSet called currentPage by skipping the appropriate number of elements and limiting the size to PAGE_SIZE. The currentPageIterator is also initialized to iterate over the current page's data.

  • Lines 93–103: The showNextPage method is called when the "Next" button is clicked. It checks if there is a next element in the currentPageIterator and moves the iterator to the next element if available. If there is no next element, it determines the current page number, increments it by 1, and calls the showPage method to display the next page. If there is a next element, it updates the UI without changing the page number.

  • Lines 105–115: The showPreviousPage method is similar to showNextPage but handles the "Previous" button click. It checks if there is a previous element in the currentPageIterator and moves the iterator to the previous element if available. If there is no previous element, it determines the current page number, decrements it by 1, and calls the showPage method to display the previous page. If there is a previous element, it updates the UI without changing the page number.

  • Lines 117–126: The updateUI method updates the UI with the current page number and the data for the current page. It sets the page label text, clears the output text area, and appends the current page's data to the text area.

Conclusion

Implementing pagination in Java is crucial for efficient data handling and enhanced user experience. By using offset-based or keyset pagination techniques, you can break down large datasets into manageable pages.

Free Resources

Copyright ©2025 Educative, Inc. All rights reserved