I have the following \"tree\" of objects:
JPanel
JScrollPane
JPanel
JPanel
JScrollPane
JTextPane
Inspired by the existing answers, I
MouseWheelEvent
verboselyJScrollPane
class cannot be extendedThe result is this piece of code:
import java.awt.Component;
import java.awt.event.MouseEvent;
import java.awt.event.MouseWheelEvent;
import java.awt.event.MouseWheelListener;
import javax.swing.JScrollBar;
import javax.swing.JScrollPane;
import javax.swing.SwingUtilities;
/**
* Passes mouse wheel events to the parent component if this component
* cannot scroll further in the given direction.
*
* This behavior is a little better than Swing's default behavior but
* still worse than the behavior of Google Chrome, which remembers the
* currently scrolling component and sticks to it until a timeout happens.
*
* @see Stack Overflow
*/
public final class MouseWheelScrollListener implements MouseWheelListener {
private final JScrollPane pane;
private int previousValue;
public MouseWheelScrollListener(JScrollPane pane) {
this.pane = pane;
previousValue = pane.getVerticalScrollBar().getValue();
}
public void mouseWheelMoved(MouseWheelEvent e) {
Component parent = pane.getParent();
while (!(parent instanceof JScrollPane)) {
if (parent == null) {
return;
}
parent = parent.getParent();
}
JScrollBar bar = pane.getVerticalScrollBar();
int limit = e.getWheelRotation() < 0 ? 0 : bar.getMaximum() - bar.getVisibleAmount();
if (previousValue == limit && bar.getValue() == limit) {
parent.dispatchEvent(SwingUtilities.convertMouseEvent(pane, e, parent));
}
previousValue = bar.getValue();
}
}
It is used like this:
JScrollPane pane = new JScrollPane();
pane.addMouseWheelListener(new MouseWheelScrollListener(pane));
Once an instance of this class is created and bound to a scroll pane, it cannot be reused for another component since it remembers the previous position of the vertical scroll bar.