This example shows how to create a pagination facility for JTable.
Main class
public class PaginationExampleMain {
public static void main(String[] args) {
JFrame frame = createFrame();
JTable table = new JTable(createObjectDataModel());
table.setAutoCreateRowSorter(true);
PaginationDataProvider<Employee> dataProvider = createDataProvider();
PaginatedTableDecorator<Employee> paginatedDecorator = PaginatedTableDecorator.decorate(table,
dataProvider, new int[]{5, 10, 20, 50, 75, 100}, 10);
frame.add(paginatedDecorator.getContentPanel());
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
private static TableModel createObjectDataModel() {
return new ObjectTableModel<Employee>() {
@Override
public Object getValueAt(Employee employee, int columnIndex) {
switch (columnIndex) {
case 0:
return employee.getId();
case 1:
return employee.getName();
case 2:
return employee.getPhoneNumber();
case 3:
return employee.getAddress();
}
return null;
}
@Override
public int getColumnCount() {
return 4;
}
@Override
public String getColumnName(int column) {
switch (column) {
case 0:
return "Id";
case 1:
return "Name";
case 2:
return "Phone";
case 3:
return "Address";
}
return null;
}
};
}
private static PaginationDataProvider<Employee> createDataProvider() {
final List<Employee> list = new ArrayList<>();
for (int i = 1; i <= 500; i++) {
Employee e = new Employee();
e.setId(i);
e.setName("name" + i);
e.setPhoneNumber("phone" + i);
e.setAddress("address " + i);
list.add(e);
}
return new PaginationDataProvider<Employee>() {
@Override
public int getTotalRowCount() {
return list.size();
}
@Override
public List<Employee> getRows(int startIndex, int endIndex) {
return list.subList(startIndex, endIndex);
}
};
}
private static JFrame createFrame() {
JFrame frame = new JFrame("JTable Pagination example");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setSize(new Dimension(600, 300));
return frame;
}
}
This example uses in memory table data but PaginationDataProvider#getRows() can get pagination row data lazily from backend/database when deeded.
The pagination decorator
public class PaginatedTableDecorator<T> {
private JTable table;
private PaginationDataProvider<T> dataProvider;
private int[] pageSizes;
private JPanel contentPanel;
private int currentPageSize;
private int currentPage = 1;
private JPanel pageLinkPanel;
private ObjectTableModel objectTableModel;
private static final int MaxPagingCompToShow = 9;
private static final String Ellipses = "...";
private PaginatedTableDecorator(JTable table, PaginationDataProvider<T> dataProvider,
int[] pageSizes, int defaultPageSize) {
this.table = table;
this.dataProvider = dataProvider;
this.pageSizes = pageSizes;
this.currentPageSize = defaultPageSize;
}
public static <T> PaginatedTableDecorator<T> decorate(JTable table,
PaginationDataProvider<T> dataProvider,
int[] pageSizes, int defaultPageSize) {
PaginatedTableDecorator<T> decorator = new PaginatedTableDecorator<>(table, dataProvider,
pageSizes, defaultPageSize);
decorator.init();
return decorator;
}
public JPanel getContentPanel() {
return contentPanel;
}
private void init() {
initDataModel();
initPaginationComponents();
initListeners();
paginate();
}
private void initListeners() {
objectTableModel.addTableModelListener(this::refreshPageButtonPanel);
}
private void initDataModel() {
TableModel model = table.getModel();
if (!(model instanceof ObjectTableModel)) {
throw new IllegalArgumentException("TableModel must be a subclass of ObjectTableModel");
}
objectTableModel = (ObjectTableModel) model;
}
private void initPaginationComponents() {
contentPanel = new JPanel(new BorderLayout());
JPanel paginationPanel = createPaginationPanel();
contentPanel.add(paginationPanel, BorderLayout.NORTH);
contentPanel.add(new JScrollPane(table));
}
private JPanel createPaginationPanel() {
JPanel paginationPanel = new JPanel();
pageLinkPanel = new JPanel(new GridLayout(1, MaxPagingCompToShow, 3, 3));
paginationPanel.add(pageLinkPanel);
if (pageSizes != null) {
JComboBox<Integer> pageComboBox = new JComboBox<>(
Arrays.stream(pageSizes).boxed()
.toArray(Integer[]::new));
pageComboBox.addActionListener((ActionEvent e) -> {
//to preserve current rows position
int currentPageStartRow = ((currentPage - 1) * currentPageSize) + 1;
currentPageSize = (Integer) pageComboBox.getSelectedItem();
currentPage = ((currentPageStartRow - 1) / currentPageSize) + 1;
paginate();
});
paginationPanel.add(Box.createHorizontalStrut(15));
paginationPanel.add(new JLabel("Page Size: "));
paginationPanel.add(pageComboBox);
pageComboBox.setSelectedItem(currentPageSize);
}
return paginationPanel;
}
private void refreshPageButtonPanel(TableModelEvent tme) {
pageLinkPanel.removeAll();
int totalRows = dataProvider.getTotalRowCount();
int pages = (int) Math.ceil((double) totalRows / currentPageSize);
ButtonGroup buttonGroup = new ButtonGroup();
if (pages > MaxPagingCompToShow) {
addPageButton(pageLinkPanel, buttonGroup, 1);
if (currentPage > (pages - ((MaxPagingCompToShow + 1) / 2))) {
//case: 1 ... n->lastPage
pageLinkPanel.add(createEllipsesComponent());
addPageButtonRange(pageLinkPanel, buttonGroup, pages - MaxPagingCompToShow + 3, pages);
} else if (currentPage <= (MaxPagingCompToShow + 1) / 2) {
//case: 1->n ...lastPage
addPageButtonRange(pageLinkPanel, buttonGroup, 2, MaxPagingCompToShow - 2);
pageLinkPanel.add(createEllipsesComponent());
addPageButton(pageLinkPanel, buttonGroup, pages);
} else {//case: 1 .. x->n .. lastPage
pageLinkPanel.add(createEllipsesComponent());//first ellipses
//currentPage is approx mid point among total max-4 center links
int start = currentPage - (MaxPagingCompToShow - 4) / 2;
int end = start + MaxPagingCompToShow - 5;
addPageButtonRange(pageLinkPanel, buttonGroup, start, end);
pageLinkPanel.add(createEllipsesComponent());//last ellipsis
addPageButton(pageLinkPanel, buttonGroup, pages);//last page link
}
} else {
addPageButtonRange(pageLinkPanel, buttonGroup, 1, pages);
}
pageLinkPanel.getParent().validate();
pageLinkPanel.getParent().repaint();
}
private Component createEllipsesComponent() {
return new JLabel(Ellipses, SwingConstants.CENTER);
}
private void addPageButtonRange(JPanel parentPanel, ButtonGroup buttonGroup, int start, int end) {
for (; start <= end; start++) {
addPageButton(parentPanel, buttonGroup, start);
}
}
private void addPageButton(JPanel parentPanel, ButtonGroup buttonGroup, int pageNumber) {
JToggleButton toggleButton = new JToggleButton(Integer.toString(pageNumber));
toggleButton.setMargin(new Insets(1, 3, 1, 3));
buttonGroup.add(toggleButton);
parentPanel.add(toggleButton);
if (pageNumber == currentPage) {
toggleButton.setSelected(true);
}
toggleButton.addActionListener(ae -> {
currentPage = Integer.parseInt(ae.getActionCommand());
paginate();
});
}
private void paginate() {
int startIndex = (currentPage - 1) * currentPageSize;
int endIndex = startIndex + currentPageSize;
if (endIndex > dataProvider.getTotalRowCount()) {
endIndex = dataProvider.getTotalRowCount();
}
List<T> rows = dataProvider.getRows(startIndex, endIndex);
objectTableModel.setObjectRows(rows);
objectTableModel.fireTableDataChanged();
}
}
Output
Example ProjectDependencies and Technologies Used:
|
|