Swing: Creating a draggable component...?

ivan_ivanovich_ivanoff picture ivan_ivanovich_ivanoff · May 17, 2009 · Viewed 16.2k times · Source

I searched the web for examples of draggable Swing components, but I found either incomplete or non-working examples.

What I need is a Swing component that can be dragged by the mouse inside an other component. While being dragged, it should already change its position, not just 'jump' to its destination.

I would appreciate examples which work without non-standard APIs.

Thank you.

Answer

ivan_ivanovich_ivanoff picture ivan_ivanovich_ivanoff · May 17, 2009

I propose a simple, but well-working solution, found out by myself ;)

What do I do?

  • When mouse is pressed, I record the cursor's position on screen, and the component's position.
  • When mouse is dragged, I calculate the difference between new and old cursor's position on screen, and move the component by this difference.

Tested with latest JDK 6 unter Linux (OpenSuse, KDE3),
but hey, it's Java Swing, should work equally everywhere.

Here goes the code:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.border.*;

public class MyDraggableComponent
    extends JComponent {

  private volatile int screenX = 0;
  private volatile int screenY = 0;
  private volatile int myX = 0;
  private volatile int myY = 0;

  public MyDraggableComponent() {
    setBorder(new LineBorder(Color.BLUE, 3));
    setBackground(Color.WHITE);
    setBounds(0, 0, 100, 100);
    setOpaque(false);

    addMouseListener(new MouseListener() {

      @Override
      public void mouseClicked(MouseEvent e) { }

      @Override
      public void mousePressed(MouseEvent e) {
        screenX = e.getXOnScreen();
        screenY = e.getYOnScreen();

        myX = getX();
        myY = getY();
      }

      @Override
      public void mouseReleased(MouseEvent e) { }

      @Override
      public void mouseEntered(MouseEvent e) { }

      @Override
      public void mouseExited(MouseEvent e) { }

    });
    addMouseMotionListener(new MouseMotionListener() {

      @Override
      public void mouseDragged(MouseEvent e) {
        int deltaX = e.getXOnScreen() - screenX;
        int deltaY = e.getYOnScreen() - screenY;

        setLocation(myX + deltaX, myY + deltaY);
      }

      @Override
      public void mouseMoved(MouseEvent e) { }

    });
  }

}

public class Main {

  public static void main(String[] args) {
    JFrame f = new JFrame("Swing Hello World");

    // by doing this, we prevent Swing from resizing
    // our nice component
    f.setLayout(null);

    MyDraggableComponent mc = new MyDraggableComponent();
    f.add(mc);

    f.setSize(500, 500);

    f.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    f.setVisible(true);
  }

}