The reason this occurs is because the code does not recognize that
even though the mouse does not physically move on the screen, the
cursor position has changed relative to the new JTree position. The
fix is to make sure that the autoscroller always looks at the correct
mouse position. I did this by storing the screen coordinates of the
mouse position, then scrolling the JTree, then converting the
coordinates back into the JTrees coordiate space.
This problem can be worked around, but it does take some effort. Here
is the code I used to solve this problem. I hope that it is helpful
to others who may have seen the same problem.
-Andy
<Sample Code>
Create a subclass of DropTarget. Override the
createDropTargetAutoScroller() method as follows.
protected DropTargetAutoScroller createDropTargetAutoScroller(
Component c, Point p) {
return new MyDropTargetAutoScroller(c, p);
}
Now create a nested subclass of the nested protected class:
DropTargetAutoScroller.
This is almost entirely copied from the JDK Source Code as provided by
SUN. (I take no credit for the deprecated method usage!)
/**
* construct a DropTargetAutoScroller
* <P>
* @param c the <code>Component</code>
* @param p the <code>Point</code>
*/
protected MyDropTargetAutoScroller(Component c, Point p)
{
super(c, p);
super.stop();
component = c;
autoScroll = (Autoscroll)component;
java.awt.Toolkit t =
java.awt.Toolkit.getDefaultToolkit();
Integer initial = new Integer(100);
Integer interval = new Integer(100);
try {
initial =
(Integer)t.getDesktopProperty("DnD.Autoscroll.initialDelay");
} catch (Exception e) {
// ignore
}
try {
interval =
(Integer)t.getDesktopProperty("DnD.Autoscroll.interval");
} catch (Exception e) {
// ignore
}
timer = new Timer(interval.intValue(), this);
timer.setCoalesce(true);
timer.setInitialDelay(initial.intValue());
locn = p;
prev = p;
screenLocation = new Point(p);
SwingUtilities.convertPointToScreen(screenLocation,
c);
try {
hysteresis =
((Integer)t.getDesktopProperty("DnD.Autoscroll.cursorHysteresis")).intValue();
} catch (Exception e) {
// ignore
}
timer.start();
}
/**
* update the geometry of the autoscroll region
*/
private void updateRegion() {
Insets i = autoScroll.getAutoscrollInsets();
Dimension size = component.getSize();
if (size.width != outer.width || size.height !=
outer.height)
outer.reshape(0, 0, size.width, size.height);
if (inner.x != i.left || inner.y != i.top)
inner.setLocation(i.left, i.top);
int newWidth = size.width - (i.left + i.right);
int newHeight = size.height - (i.top + i.bottom);
if (newWidth != inner.width || newHeight !=
inner.height)
inner.setSize(newWidth, newHeight);
}
/**
* cause autoscroll to occur
* <P>
* @param newLocn the <code>Point</code>
*/
protected synchronized void updateLocation(Point newLocn)
{
prev = locn;
locn = newLocn;
screenLocation = new Point(locn);
SwingUtilities.convertPointToScreen(screenLocation,
component);
if (Math.abs(locn.x - prev.x) > hysteresis ||
Math.abs(locn.y - prev.y) > hysteresis) {
if (timer.isRunning()) {
timer.stop();
}
} else {
if (!timer.isRunning()) {
timer.start();
}
};
}
/**
* cause autoscrolling to stop
*/
protected void stop() {
timer.stop();
}
/**
* cause autoscroll to occur
* <P>
* @param e the <code>ActionEvent</code>
*/
public synchronized void actionPerformed(ActionEvent e) {
updateRegion();
Point componentLocation = new Point(screenLocation);
SwingUtilities.convertPointFromScreen(componentLocation,
component);
if (outer.contains(componentLocation) &&
!inner.contains(componentLocation)) {
autoScroll.autoscroll(componentLocation);
}
}
/*
* fields
*/
private Window window;
private Canvas canvas;
private Component component;
private Autoscroll autoScroll;
private Timer timer;
private Point locn;
private Point prev;
private Point screenLocation;
private Rectangle outer = new Rectangle();
private Rectangle inner = new Rectangle();
private int hysteresis = 10;
}
};