Skip to content

Instantly share code, notes, and snippets.

@aterai
Created December 28, 2016 05:57
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save aterai/997c15af2db378efa4cd7834ee39e57e to your computer and use it in GitHub Desktop.
Save aterai/997c15af2db378efa4cd7834ee39e57e to your computer and use it in GitHub Desktop.
//package example;
//-*- mode:java; encoding:utf-8 -*-
// vim:set fileencoding=utf-8:
//@homepage@
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import javax.swing.*;
import javax.swing.Timer;
import javax.swing.tree.*;
public final class KineticScrollingViewPositionTest {
private JComponent makeUI() {
JTree tree = new JTree();
tree.setOpaque(false);
JScrollPane scroll = new JScrollPane(tree);
JViewport viewport = new JViewport() {
private boolean validateIsAdjusting;
@Override public void revalidate() {
if (validateIsAdjusting) {
return;
}
super.revalidate();
}
@Override public void setViewPosition(Point p) {
validateIsAdjusting = true;
super.setViewPosition(p);
validateIsAdjusting = false;
}
};
viewport.setView(tree);
//viewport.setScrollMode(JViewport.BACKINGSTORE_SCROLL_MODE);
viewport.setBackground(tree.getBackground());
scroll.setViewport(viewport);
MouseAdapter ma1 = new KineticScrollingListener2(tree);
viewport.addMouseMotionListener(ma1);
viewport.addMouseListener(ma1);
MouseAdapter dispatcher = new MouseAdapter() {
private void dispatchEvent(MouseEvent e) {
JComponent c = (JComponent) e.getComponent();
JComponent p = (JComponent) e.getComponent().getParent();
p.dispatchEvent(SwingUtilities.convertMouseEvent(c, e, p));
}
@Override public void mouseDragged(MouseEvent e) {
dispatchEvent(e);
}
@Override public void mouseClicked(MouseEvent e) {
dispatchEvent(e);
}
@Override public void mouseEntered(MouseEvent e) {
dispatchEvent(e);
}
@Override public void mouseExited(MouseEvent e) {
dispatchEvent(e);
}
@Override public void mousePressed(MouseEvent e) {
dispatchEvent(e);
}
@Override public void mouseReleased(MouseEvent e) {
dispatchEvent(e);
}
};
tree.addMouseMotionListener(dispatcher);
tree.addMouseListener(dispatcher);
return scroll;
}
public static void main(String... args) {
EventQueue.invokeLater(() -> {
createAndShowGUI();
});
}
public static void createAndShowGUI() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException
| IllegalAccessException | UnsupportedLookAndFeelException ex) {
ex.printStackTrace();
}
JFrame frame = new JFrame();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.getContentPane().add(new KineticScrollingViewPositionTest().makeUI());
frame.setSize(320, 240);
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
}
class KineticScrollingListener2 extends MouseAdapter implements HierarchyListener {
private static final int SPEED = 4;
private static final int DELAY = 10;
private static final double D = .8;
private final JComponent label;
private final Point startPt = new Point();
private final Point delta = new Point();
private final Cursor dc;
private final Cursor hc = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR);
private final Timer inside = new Timer(DELAY, new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
JViewport vport = (JViewport) SwingUtilities.getUnwrappedParent(label);
Point vp = vport.getViewPosition();
//System.out.format("s: %s, %s%n", delta, vp);
vp.translate(-delta.x, -delta.y);
vport.setViewPosition(vp);
if (Math.abs(delta.x) > 0 || Math.abs(delta.y) > 0) {
delta.setLocation((int)(delta.x * D), (int)(delta.y * D));
//Outside
if (vp.x < 0 || vp.x + vport.getWidth() - label.getWidth() > 0) {
delta.x = (int)(delta.x * D);
}
if (vp.y < 0 || vp.y + vport.getHeight() - label.getHeight() > 0) {
delta.y = (int)(delta.y * D);
}
} else {
//inside.stop();
((Timer) e.getSource()).stop();
if (!isInside(vport, label)) {
outside.start();
}
}
}
});
private final Timer outside = new Timer(DELAY, new ActionListener() {
@Override public void actionPerformed(ActionEvent e) {
JViewport vport = (JViewport) SwingUtilities.getUnwrappedParent(label);
Point vp = vport.getViewPosition();
//System.out.format("r: %s%n", vp);
if (vp.x < 0) {
vp.x = (int)(vp.x * D);
}
if (vp.y < 0) {
vp.y = (int)(vp.y * D);
}
if (vp.x + vport.getWidth() - label.getWidth() > 0) {
vp.x = (int)(vp.x - (vp.x + vport.getWidth() - label.getWidth()) * (1d - D));
}
if (vp.y + vport.getHeight() > label.getHeight()) {
vp.y = (int)(vp.y - (vp.y + vport.getHeight() - label.getHeight()) * (1d - D));
}
vport.setViewPosition(vp);
if (isInside(vport, label)) {
//outside.stop();
((Timer) e.getSource()).stop();
}
}
});
private static boolean isInside(JViewport vport, JComponent comp) {
Point vp = vport.getViewPosition();
return vp.x >= 0 && vp.x + vport.getWidth() - comp.getWidth() <= 0
&& vp.y >= 0 && vp.y + vport.getHeight() - comp.getHeight() <= 0;
}
protected KineticScrollingListener2(JComponent comp) {
super();
this.label = comp;
this.dc = comp.getCursor();
}
@Override public void mousePressed(MouseEvent e) {
e.getComponent().setCursor(hc);
startPt.setLocation(e.getPoint());
inside.stop();
outside.stop();
}
@Override public void mouseDragged(MouseEvent e) {
Point pt = e.getPoint();
JViewport vport = (JViewport) SwingUtilities.getUnwrappedParent(label);
Point vp = vport.getViewPosition();
vp.translate(startPt.x - pt.x, startPt.y - pt.y);
vport.setViewPosition(vp);
delta.setLocation(SPEED * (pt.x - startPt.x), SPEED * (pt.y - startPt.y));
startPt.setLocation(pt);
}
@Override public void mouseReleased(MouseEvent e) {
e.getComponent().setCursor(dc);
JViewport vport = (JViewport) SwingUtilities.getUnwrappedParent(label);
if (isInside(vport, label)) {
inside.start();
} else {
outside.start();
}
}
@Override public void hierarchyChanged(HierarchyEvent e) {
if ((e.getChangeFlags() & HierarchyEvent.DISPLAYABILITY_CHANGED) != 0 && !e.getComponent().isDisplayable()) {
inside.stop();
outside.stop();
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment