Code
class RearrangingHandler extends MouseAdapter {
private static final Rectangle R1 = new Rectangle();
private static final Rectangle R2 = new Rectangle();
private final Rectangle prevRect = new Rectangle();
private final int gestureMotionThreshold = DragSource.getDragThreshold();
private final JWindow window = new JWindow();
private final Point startPt = new Point();
private int index = -1;
private Component draggingComponent;
private Component gap;
private final Point dragOffset = new Point();
public RearrangingHandler() {
super();
window.setBackground(new Color(0x0, true));
}
@Override public void mousePressed(MouseEvent e) {
if (((JComponent) e.getComponent()).getComponentCount() <= 1) {
startPt.setLocation(0, 0);
} else {
startPt.setLocation(e.getPoint());
}
}
private void startDragging(JComponent parent, Point pt) {
Component c = parent.getComponentAt(pt);
index = parent.getComponentZOrder(c);
if (Objects.equals(c, parent) || index < 0) {
return;
}
draggingComponent = c;
Dimension d = draggingComponent.getSize();
Point dp = draggingComponent.getLocation();
dragOffset.setLocation(pt.x - dp.x, pt.y - dp.y);
gap = Box.createRigidArea(d);
swapComponentLocation(parent, c, gap, index);
window.add(draggingComponent);
// window.setSize(d);
window.pack();
updateWindowLocation(pt, parent);
window.setVisible(true);
}
private void updateWindowLocation(Point pt, JComponent parent) {
if (window.isVisible() && Objects.nonNull(draggingComponent)) {
Point p = new Point(pt.x - dragOffset.x, pt.y - dragOffset.y);
SwingUtilities.convertPointToScreen(p, parent);
window.setLocation(p);
}
}
private int getTargetIndex(Rectangle r, Point pt, int i) {
int ht2 = (int) (.5 + r.height * .5);
R1.setBounds(r.x, r.y, r.width, ht2);
R2.setBounds(r.x, r.y + ht2, r.width, ht2);
if (R1.contains(pt)) {
prevRect.setBounds(R1);
return i - 1 > 0 ? i : 0;
} else if (R2.contains(pt)) {
prevRect.setBounds(R2);
return i;
}
return -1;
}
private static void swapComponentLocation(
Container parent, Component remove, Component add, int idx) {
parent.remove(remove);
parent.add(add, idx);
parent.revalidate();
parent.repaint();
}
@Override public void mouseDragged(MouseEvent e) {
Point pt = e.getPoint();
JComponent parent = (JComponent) e.getComponent();
if (Objects.isNull(draggingComponent)) {
if (startPt.distance(pt) > gestureMotionThreshold) {
startDragging(parent, pt);
}
return;
}
updateWindowLocation(pt, parent);
if (prevRect.contains(pt)) {
return;
}
for (int i = 0; i < parent.getComponentCount(); i++) {
Component c = parent.getComponent(i);
Rectangle r = c.getBounds();
if (Objects.equals(c, gap) && r.contains(pt)) {
return;
}
int tgt = getTargetIndex(r, pt, i);
if (tgt >= 0) {
swapComponentLocation(parent, gap, gap, tgt);
return;
}
}
// System.out.println("outer");
parent.remove(gap);
parent.revalidate();
}
@Override public void mouseReleased(MouseEvent e) {
startPt.setLocation(0, 0);
dragOffset.setLocation(0, 0);
prevRect.setBounds(0, 0, 0, 0);
window.setVisible(false);
Point pt = e.getPoint();
JComponent parent = (JComponent) e.getComponent();
Component cmp = draggingComponent;
draggingComponent = null;
for (int i = 0; i < parent.getComponentCount(); i++) {
Component c = parent.getComponent(i);
if (Objects.equals(c, gap)) {
swapComponentLocation(parent, gap, cmp, i);
return;
}
int tgt = getTargetIndex(c.getBounds(), pt, i);
if (tgt >= 0) {
swapComponentLocation(parent, gap, cmp, tgt);
return;
}
}
if (parent.getParent().getBounds().contains(pt)) {
swapComponentLocation(parent, gap, cmp, parent.getComponentCount());
} else {
swapComponentLocation(parent, gap, cmp, index);
}
}
}
References