16

I tried to make any Component draggable by simply adding mouse listeners and using the setLocation function of java.awt.Component. I started with JButton to test if it were possible the way i thought.

Here is a code example for what I am trying to do:

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

public class DragButton extends JButton{

private volatile int draggedAtX, draggedAtY;

public DragButton(String text){
    super(text);
    setDoubleBuffered(false);
    setMargin(new Insets(0, 0, 0, 0));
    setSize(25, 25);
    setPreferredSize(new Dimension(25, 25));

    addMouseListener(new MouseAdapter(){
        public void mousePressed(MouseEvent e){
            draggedAtX = e.getX() - getLocation().x;
            draggedAtY = e.getY() - getLocation().y;
        }
    });

    addMouseMotionListener(new MouseMotionAdapter(){
        public void mouseDragged(MouseEvent e){
            setLocation(e.getX() - draggedAtX, e.getY() - draggedAtY);
        }
    });
}

public static void main(String[] args){
    JFrame frame = new JFrame("DragButton");
    frame.setLayout(null);
    frame.getContentPane().add(new DragButton("1"));
    frame.getContentPane().add(new DragButton("2"));
    frame.getContentPane().add(new DragButton("3"));
    frame.setSize(300, 300);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
    }
}

Somehow this fails to work properly and I don't get why. The actual distance dragged is half the distance of the mouse movement and it flickers around that distance while dragging as if two mouse positions are competing over the MouseMotionListener.

May anyone help a swing/awt noob? =) Many thanks in advance.

Edit:

Ok, so the problem was that I did not know that the event would refire at each mouse location with the position being relative(!) to the firing JComponent. So this is the corrected and working code:

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

public class DragButton extends JButton{

    private volatile int draggedAtX, draggedAtY;

    public DragButton(String text){
        super(text);
        setDoubleBuffered(false);
        setMargin(new Insets(0, 0, 0, 0));
        setSize(25, 25);
        setPreferredSize(new Dimension(25, 25));

        addMouseListener(new MouseAdapter(){
            public void mousePressed(MouseEvent e){
                draggedAtX = e.getX();
                draggedAtY = e.getY();
            }
        });

        addMouseMotionListener(new MouseMotionAdapter(){
            public void mouseDragged(MouseEvent e){
                setLocation(e.getX() - draggedAtX + getLocation().x,
                        e.getY() - draggedAtY + getLocation().y);
            }
        });
    }

    public static void main(String[] args){
        JFrame frame = new JFrame("DragButton");
        frame.setLayout(null);
        frame.getContentPane().add(new DragButton("1"));
        frame.getContentPane().add(new DragButton("2"));
        frame.getContentPane().add(new DragButton("3"));
        frame.setSize(300, 300);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}

Thanks Adel for your efforts and mKorbel for the link.

Stephan
  • 163
  • 1
  • 1
  • 6
  • See also [`ChessBoard`](http://stackoverflow.com/a/2562685/230513). – trashgod Jan 27 '12 at 16:44
  • 1
    Yep, glass pane is certainly the way to go here, but I tried to keep the example as simple as possible, but still compilable. I hope this won't confuse future readers though. USE GLASSPANE! (Or a [layered pane](http://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html) with its DRAG_LAYER) – Stephan Feb 18 '12 at 21:54

4 Answers4

13

You have to move with JComponent, I miss this definitions in voids mousePressed/mouseDragged; in other hands, there nothing better around as @[camickr][1] excellent code for ComponentMover.

trashgod
  • 203,806
  • 29
  • 246
  • 1,045
mKorbel
  • 109,525
  • 20
  • 134
  • 319
  • Oh my god, thank you so much for that link! The first few sentances made me hit my head. ^^ I edited my post to show the correct code. – Stephan Jan 31 '12 at 23:19
  • Well I could not, quite recently. ;) – Stephan Feb 25 '12 at 03:04
  • +1 for ComponentMover. Saved me a lot of trouble. Thanks – Emmanuel John Nov 15 '14 at 17:09
  • I know this is old, but do you know how to get ComponentMover to work on multiple monitors? – Ryan Sep 23 '16 at 05:35
  • @Ryan no idea right now, nor in Java8 (can't awaiting some changes in comparing with Java6), is there some issue with, then create a new question with description about issue, link to code repository, your code and Java version, event. with Native OS, maybe someone can test that :-) – mKorbel Sep 23 '16 at 15:22
5
import javax.swing.*;
import java.awt.event.*;    

public class movingButton extends JFrame{

    private JButton button ;

    public movingButton ()
    {
     super("Position helper");
       super.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
       super.setSize(500,520);
       super.setVisible(true);
       super.setLayout(null);
       button = new JButton ("drag me ");
       add(button);
       button.setBounds(100, 100, 150, 40);         
       button.addMouseMotionListener(new MouseAdapter(){

            public void mouseDragged(MouseEvent E)
            {
               int X=E.getX()+button.getX();
               int Y=E.getY()+button.getY;
               button.setBounds(X,Y,150,40);
            }
        });
    }

    public static void main (String x[])
    {           
        new movingButton();
    }
}
shadi
  • 51
  • 1
  • 3
  • Works and adequate for what I need to do but mouse pointer is offset from the actual component when dragging? Any ideas? – Emmanuel John Nov 14 '14 at 15:28
2

Why don't you use the java Transferable interface instead?

Here's a tutorial on how to do it: http://www.javaworld.com/javaworld/jw-03-1999/jw-03-dragndrop.html

Adel Boutros
  • 10,205
  • 7
  • 55
  • 89
  • Does java.awt.dnd support the moving animation of components? I do not need the data dropping portion of Drag and Drop (well I do need it but thats a minor problem) rather than the animation itself. The most tutorials I found only described the data transfer portion, where only the cursor indicates a drag and drop. I want the whole Component to move. (sry for my english^^) – Stephan Jan 27 '12 at 17:37
  • @Stephan Transferable comes from the package _java.awt.datatransfer_ So it can support drag and drop in _awt_ – Adel Boutros Jan 27 '12 at 17:54
  • Sry, but this does not answer my question, however I found a working example of a drag and drop animation(!) using java.awt.dnd and java.awt.datatransfer: [link](http://weblogs.java.net/blog/gfx/archive/2005/10/drag_and_drop_e.html). Working through it is not fun though, since he only linked his source code. – Stephan Jan 27 '12 at 20:21
  • I read through those articles but in my understanding it is not common to make a drag animation without using `Graphics` and drawing it manually. So I even more want my approach to work. =) If it is even possible that way, that is... – Stephan Jan 29 '12 at 12:48
  • The interface i proposed to you is what we are using in your company. The only problem is that it's not me who does it, i just use it. So can't help you on that. Sorry – Adel Boutros Jan 29 '12 at 13:33
0

It is better if you would do

int X=E.getX() + button.getX();
int Y=E.getY() + button.getY();
Eel Lee
  • 3,513
  • 2
  • 31
  • 49
Marco
  • 1
  • I don't think your answer is proper - firstly you don't provide any comment about using that snippet, and secondly you're using different letter size. – Eel Lee Nov 14 '13 at 15:40