import java.awt.BorderLayout;
import java.awt.Component;
import java.awt.Container;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.awt.event.MouseMotionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
public class Test implements Runnable {
public static void main(String[] args) {
EventQueue.invokeLater(new Test());
}
@Override
public void run() {
final JPanel dragArea = new JPanel(null);
final JPanel view = new JPanel(new BorderLayout());
final DragPane drag = new DragPane(view);
final JButton button = new JButton("Make a clone");
button.setSize(button.getPreferredSize());
dragArea.add(button);
view.add(dragArea, BorderLayout.CENTER);
view.add(createTestPanel(), BorderLayout.SOUTH);
button.addMouseListener(new MouseAdapter() {
@Override
public void mousePressed(MouseEvent evt) {
JButton clone = createTestButton();
drag.setDrag(clone, button.getParent(), button.getLocation(), evt.getPoint(),
new DragPane.DragFinishedHandler() {
@Override
public void dragFinished(DragPane pane, Component c, Point location) {
c.setLocation(SwingUtilities.convertPoint(pane, location, dragArea));
dragArea.add(c);
}
});
}
});
JFrame frm = new JFrame("Test");
frm.setLocationByPlatform(true);
frm.setContentPane(drag);
frm.setSize(600, 400);
frm.setVisible(true);
}
private static JButton createTestButton() {
return new JButton("Drag me");
}
private static JPanel createTestPanel() {
JPanel south = new JPanel();
for (int i = 0; i < 6; i++) {
south.add(new JButton("Button " + i));
}
return south;
}
}
class DragPane extends JPanel {
private final Component view;
private final DragGlassPane glassPane;
private Component drag;
private Point dragOff;
public static interface DragFinishedHandler {
public void dragFinished(DragPane pane, Component c, Point location);
}
public DragPane(Component c) {
super(null);
glassPane = new DragGlassPane();
view = c;
add(c);
glassPane.addMouseMotionListener(new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent me) {
handleEvent(me, 0, 0);
}
@Override
public void mouseMoved(MouseEvent me) {
handleEvent(me, 0, 0);
}
});
}
public Component getView() {
return view;
}
private void handleEvent(MouseEvent evt, int dx, int dy) {
drag.setLocation(evt.getX() - dragOff.x + dx, evt.getY() - dragOff.y + dy);
}
@Override
public Dimension getPreferredSize() {
return view.getPreferredSize();
}
@Override
public void doLayout() {
for (Component c : getComponents()) {
if (c == glassPane || c == view) {
c.setSize(getSize());
}
}
}
public static DragPane getDragPane(Component c) {
Container cont = c.getParent();
while (cont != null) {
if (cont instanceof DragPane) {
return (DragPane) cont;
}
cont = cont.getParent();
}
return null;
}
private static Point getLocationOnDragPane(Component c) {
Point p = new Point(c.getLocation());
Container cont = c.getParent();
while (cont != null) {
p.x += cont.getX();
p.y += cont.getY();
cont = cont.getParent();
if (cont instanceof DragPane) {
break;
}
}
return p;
}
public void setDrag(Component c, Container cont, Point relLocation, Point off,
final DragFinishedHandler handler) {
if (drag != null) {
return;
}
Point loc = getLocationOnDragPane(cont);
loc.translate(relLocation.x, relLocation.y);
drag = c;
dragOff = off;
add(glassPane, 0);
add(c, 0);
c.setLocation(loc);
c.setSize(c.getPreferredSize());
final MouseMotionListener motion = new MouseMotionListener() {
@Override
public void mouseDragged(MouseEvent me) {
handleEvent(me, drag.getX(), drag.getY());
}
@Override
public void mouseMoved(MouseEvent me) {
handleEvent(me, drag.getX(), drag.getY());
}
};
final MouseListener mouse = new MouseAdapter() {
@Override
public void mouseReleased(MouseEvent evt) {
stopDrag(motion, this, handler);
}
};
glassPane.addMouseListener(mouse);
drag.addMouseMotionListener(motion);
drag.addMouseListener(mouse);
doLayout();
}
private void stopDrag(MouseMotionListener motion, MouseListener mouse, DragFinishedHandler handler) {
drag.removeMouseMotionListener(motion);
drag.removeMouseListener(mouse);
glassPane.removeMouseListener(mouse);
Point p = drag.getLocation();
remove(drag);
remove(glassPane);
handler.dragFinished(this, drag, p);
drag = null;
repaint();
}
private class DragGlassPane extends JPanel {
public DragGlassPane() {
super(null);
setOpaque(false);
}
}
}