Paiku Han
Paiku Han

Reputation: 583

What is the best UI element dragging algorithm

I made a GUI application but I am stuck with a workaround algorithm to drag/move ui element relatively to another surface (screen, canvas, etc.). In my case I use it for a window relative to the screen, but that's beside the point because this algorithm should work anywhere possible. Here is my algorithm:

code-listing-1.

MouseMotionAdapter(){
            int prevX = -1000, prevY = -1000, getX, getY;
            public void mouseDragged(MouseEvent e) {
              //if initial cursor position isn't set 
                if(prevX==-1000){
                    prevX = e.getLocationOnScreen().x;
                    prevY = e.getLocationOnScreen().y;
                    getX = e.getX();
                    getY = e.getY();
                }
               //move element to new position 
                theFrame.setBounds(theFrame.getBounds().x+e.getX()-getX, theFrame.getBounds().y+e.getY()-getY, 880, 583);
                prevX=e.getLocationOnScreen().x;
                prevY=e.getLocationOnScreen().y;
            }

The trouble with this algorithm is that the mouse cursor position is definitely fixed relatively to the element and if I try to move/drag the element clicking in another position/part of the element the whole element moves so that the mouse cursor is positioned at the "initial position", which is not the behaviour I want (I want it to have the behaviour we mostly know like when we move an icon on desktop or a window on the screen, etc.)

Can anyone help with that? Thanks in advance.

Upvotes: 2

Views: 403

Answers (1)

Marco13
Marco13

Reputation: 54639

The usual approach in such a case is to compute the difference between the current and the previous position. This difference is then "the movement", that is added to the position of the dragged object.

(BTW: You seem to not use the prev... values in your computation at all!)

Inside a MouseMotionListener, this could roughly look as follows:

class MouseDraggingControl implements MouseMotionListener 
{
    private Point previousPoint = new Point();

    @Override 
    public void mouseMoved(MouseEvent e)
    {
        previousPoint = e.getPoint();
    }

    @Override 
    public void mouseDragged(MouseEvent e)
    {
        int movementX = e.getX() - previousPoint.x;
        int movementY = e.getY() - previousPoint.y;

        doMovement(movementX, movementY);

        previousPoint = e.getPoint();
    }
}

In your case, the doMovement method might be implemented like this:

private void doMovement(int movementX, int movementY)
{
    int oldX = theFrame.getX();
    int oldY = theFrame.getY();
    int newX = oldX + movementX;
    int newY = oldY + movementY;
    theFrame.setLocation(newX, newY);
}

(or similar, using the getBounds/setBounds calls)


EDIT If the mouse motion listener is attached directly to the component that should be dragged, you might have to use the "location on screen" instead:

class MouseDraggingControl implements MouseMotionListener 
{
    private Point previousPoint = new Point();

    @Override 
    public void mouseMoved(MouseEvent e)
    {
        previousPoint = e.getLocationOnScreen();
    }

    @Override 
    public void mouseDragged(MouseEvent e)
    {
        Point p = e.getLocationOnScreen();
        int movementX = p.x - previousPoint.x;
        int movementY = p.y - previousPoint.y;

        doMovement(movementX, movementY);

        previousPoint = e.getLocationOnScreen();
    }
}

If this does not solve your issue, I'd like to emphasize the comment from MadProgrammer: An example that demonstrates your actual problem would help here.

Upvotes: 3

Related Questions