0

I have a JTable wrapped into a JScrollPane. When I scroll to the top or bottom and continue to scroll, I want to be able to detect that in order to possibly load more items at the beginning or end since it is too expensive/not practical to load all items at once. The AdjustmentListener is not fired when the JScrollPane does not move (e.g. when it is already at the top or bottom):

scrollPane.getVerticalScrollBar().addAdjustmentListener(adjustmentEvent ->
{
    int value = adjustmentEvent.getValue();
    System.out.println(value); // Prints 0 e.g. when the top has been reached
});

However, I need to know when the user scrolls even though the end/start has already been reached.

How can this be done?

BullyWiiPlaza
  • 17,329
  • 10
  • 113
  • 185
  • You could get the position of your pane and compare it with your pane size – Turtle May 23 '17 at 09:43
  • *"When I scroll to the top or bottom and continue to scroll, I want to be able to detect that in order to possibly load more items.."* Why not load them all at start-up? How many are there likely to be? – Andrew Thompson May 23 '17 at 09:49
  • @Nathan: Yes but how do I detect when the user tries to scroll up/down to load more elements then? AndrewThompson: It's not feasible to load them all at once, it can be up to 1 billion rows over the network. – BullyWiiPlaza May 23 '17 at 10:25
  • @BullyWiiPlaza You could implement a mouselistener to detect the drag and drop of the scrollbar and the mouse wheel event. That means doing it from scratch though. – Turtle May 23 '17 at 12:08
  • [for example](https://stackoverflow.com/q/8197261/714968) – mKorbel May 23 '17 at 16:49

1 Answers1

3

I suggest using a change listener on the JViewport of the scroll pane. The following example shows how to proceed. Please note that shouldCheck might be used to prevent false notifications (in my sample top is printed three times upon startup. If you run the sample and move the slider to the top and bottom a corresponding text is printed.

Screenshot with running sample

package com.thomaskuenneth;

import javax.swing.*;

public class Main {

    static boolean shouldCheck = true;

    public static void main(String[] args) {
        SwingUtilities.invokeLater(() -> {
            JFrame f = new JFrame("Demo");
            f.getContentPane().add(createUI());
            f.pack();
            f.setLocationRelativeTo(null);
            f.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
            f.setVisible(true);
        });
    }

    static JComponent createUI() {
        String[][] rowData = new String[200][10];
        String[] columnNames = new String[10];
        for (int i = 0; i < 200; i++) {
            for (int j = 0; j < 10; j++) {
                if (i == 0) {
                    columnNames[j] = String.format("#%d", j);
                }
                rowData[i][j] = String.format("%d - %d", i, j);
            }
        }
        JTable t = new JTable(rowData, columnNames);
        JScrollPane sp = new JScrollPane(t);
        JScrollBar sb = sp.getVerticalScrollBar();
        JViewport vp = sp.getViewport();
        vp.addChangeListener((l) -> {
            if (!shouldCheck) {
                return;
            }
            if (sb.getValue() == sb.getMinimum()) {
                System.out.println("top");
            } else if (sb.getValue() + sb.getVisibleAmount() == sb.getMaximum()) {
                System.out.println("bottom");
            }
        });
        return sp;
    }
}