Code
class StickyLayerUI extends LayerUI<JScrollPane> {
private final JPanel renderer = new JPanel();
private int currentHeaderIdx = -1;
private int nextHeaderIdx = -1;
@Override public void installUI(JComponent c) {
super.installUI(c);
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(
AWTEvent.MOUSE_WHEEL_EVENT_MASK
| AWTEvent.MOUSE_MOTION_EVENT_MASK);
}
}
@Override public void uninstallUI(JComponent c) {
if (c instanceof JLayer) {
((JLayer<?>) c).setLayerEventMask(0);
}
super.uninstallUI(c);
}
@Override protected void processMouseMotionEvent(
MouseEvent e, JLayer<? extends JScrollPane> l) {
super.processMouseMotionEvent(e, l);
Component c = l.getView().getViewport().getView();
if (e.getID() == MouseEvent.MOUSE_DRAGGED && c instanceof JList) {
update((JList<?>) c);
}
}
@Override protected void processMouseWheelEvent(
MouseWheelEvent e, JLayer<? extends JScrollPane> l) {
super.processMouseWheelEvent(e, l);
Component c = l.getView().getViewport().getView();
if (c instanceof JList) {
update((JList<?>) c);
}
}
private void update(JList<?> list) {
int idx = list.getFirstVisibleIndex();
if (idx >= 0) {
currentHeaderIdx = getHeaderIndex1(list, idx);
nextHeaderIdx = getNextHeaderIndex1(list, idx);
} else {
currentHeaderIdx = -1;
nextHeaderIdx = -1;
}
}
@Override public void paint(Graphics g, JComponent c) {
super.paint(g, c);
JList<?> list = getList(c);
if (list != null && currentHeaderIdx >= 0) {
JScrollPane scroll = (JScrollPane) ((JLayer<?>) c).getView();
Rectangle headerRect = scroll.getViewport().getBounds();
headerRect.height = list.getFixedCellHeight();
Graphics2D g2 = (Graphics2D) g.create();
int firstVisibleIdx = list.getFirstVisibleIndex();
if (firstVisibleIdx + 1 == nextHeaderIdx) {
Dimension d = headerRect.getSize();
Component c1 = getComponent(list, currentHeaderIdx);
Rectangle r1 = getHeaderRect(list, firstVisibleIdx, c, d);
SwingUtilities.paintComponent(g2, c1, renderer, r1);
Component c2 = getComponent(list, nextHeaderIdx);
Rectangle r2 = getHeaderRect(list, nextHeaderIdx, c, d);
SwingUtilities.paintComponent(g2, c2, renderer, r2);
} else {
Component c1 = getComponent(list, currentHeaderIdx);
SwingUtilities.paintComponent(g2, c1, renderer, headerRect);
}
g2.dispose();
}
}
private static JList<?> getList(JComponent layer) {
JList<?> list = null;
if (layer instanceof JLayer) {
JScrollPane scroll = (JScrollPane) ((JLayer<?>) layer).getView();
Component view = scroll.getViewport().getView();
if (view instanceof JList) {
list = (JList<?>) view;
}
}
return list;
}
private static int getHeaderIndex1(JList<?> list, int start) {
return list.getNextMatch("0", start, Position.Bias.Backward);
}
private static int getNextHeaderIndex1(JList<?> list, int start) {
return list.getNextMatch("0", start, Position.Bias.Forward);
}
private static Rectangle getHeaderRect(
JList<?> list, int i, Component dst, Dimension d) {
Rectangle r = SwingUtilities.convertRectangle(
list, list.getCellBounds(i, i), dst);
r.setSize(d);
return r;
}
private static <E> Component getComponent(JList<E> list, int idx) {
E value = list.getModel().getElementAt(idx);
ListCellRenderer<? super E> r = list.getCellRenderer();
Component c = r.getListCellRendererComponent(
list, value, idx, false, false);
c.setBackground(Color.GRAY);
c.setForeground(Color.WHITE);
return c;
}
}
References