简体   繁体   中英

How do I get images to move without them first jumping to position of the mouse cursor when using mouseDragged?

I have a program where I am able to move images around on the screen by clicking and dragging. The only problem is, when I click an image and start to drag it around on my panel, the image first jumps to the position of the mouse cursor. How do I prevent this, so that the image is simply moved no matter where I click on the image? I can only get the mouse cursor to either jump to under the mouse arrow when starting to drag, or over the mouse arrow when starting to drag, or set to the middle of the image to drag.

I am moving an Image object of the Image class in another class with the following function:

moveImage(selected,x,y);

where x and y are coordinates from the mouseDragged method. This is my image class:

import javax.imageio.ImageIO;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

class Image {

    private int x;
    private int y;
    private BufferedImage image;
    private StringBuffer filepath;
    private boolean isTurned;

    public Image(int x, int y, String filepath) throws IOException {
        this.filepath = new StringBuffer(filepath);
        this.x = x;
        this.y = y;
        this.image = ImageIO.read(new File(String.valueOf(filepath)));
    }

    public void draw(Graphics g){

        g.drawImage(image, x, y, null);

    }

    public void undraw (Graphics g, Color c ){
        g.setColor(c);
        g.fillRect(x,y, image.getWidth(), image.getHeight());

    }

    public boolean containsXY (int x, int y){

        if ( (this.x <= x ) && (x <= (this.x+this.image.getWidth())) && (this.y <= y ) && (y <= (this.y+this.image.getHeight()))  ){

            return true;
        }

        return false;
    }

    public void move (Graphics g, int x, int y) {
        System.out.println("int x = " + x + " int y = " + y);
        System.out.println("this x = " + this.x + " this y = " + this.y);
        System.out.println("width: " + this.image.getWidth() + " height: " + this.image.getHeight());

        undraw(g, Color.WHITE);

       /* this.x = x - ((x+image.getWidth())-x);
        this.y = y -((y+image.getHeight())-y);

        this.x = x - (x-this.x);
        this.y = y - (y-this.y);

        this.x = x - (this.x+image.getWidth()-x);
        this.y = y - (this.y+image.getHeight()-y);



        this.x = this.x + (x-image.getWidth());
        this.y = this.y + (y-image.getHeight());

        this.x = x - (image.getWidth());
        this.y = y - (image.getHeight());*/

        this.x = x - (image.getWidth()/2);
        this.y = y - (image.getHeight()/2);


        draw(g);
    }

    public void turn(Graphics g) throws IOException {

        if (isTurned) {
            filepath.replace(filepath.length()-9, filepath.length(), ".gif" );
            undraw(g, Color.WHITE);
            image = ImageIO.read(new File(String.valueOf(filepath)));
            draw(g);
            isTurned = false;
        }

        else {
            filepath.replace(filepath.length()-4, filepath.length(), " back.gif" );
            undraw(g, Color.WHITE);
            image = ImageIO.read(new File(String.valueOf(filepath)));
            draw(g);
            isTurned = true;
        }
    }

}

As you can see, inside the move method, I have tried alot of different things on manipulation the incoming mouse event dragged coordinates. Right now in the code I am using

this.x = x - (image.getWidth()/2);
this.y = y - (image.getHeight()/2);

which makes the mouse cursor lock on the middle of the image when I am dragging it around which is the best I can currently do. So when I want to move an image and click in the corner of the image, it "pops" to the middle of the image and locks there while dragging the image around. But I do not want this. I want the mouse cursor to just stay on the location on the image where I clicked when I started the drag, not redraw the image somewhere else and then start the drag.

This is the class from which I call the Image object, I am calling it inside this class:s method moveImage:

import javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;

class PaintSurface extends JLabel implements MouseListener, MouseMotionListener {

    private int x, y;
    private JButton browse;
    private Collection<Image> images = new ArrayList<Image>();
    private final JFileChooser fc = new JFileChooser();
    private Image selected;

    public PaintSurface(JButton b){
        browse = b;
        addMouseListener(this);
        addMouseMotionListener(this);
        browse.addActionListener(new ActionListener() {
            @Override
            public void actionPerformed(ActionEvent e) {

                int x = fc.showOpenDialog(browse);

                if (x == JFileChooser.APPROVE_OPTION){
                    try {
                        buttonPressed(fc);

                    } catch (IOException e1) {
                        e1.printStackTrace();
                    }
                }

                else if (x ==JFileChooser.CANCEL_OPTION){
                    System.out.println("No file selected.");
                }
            }
        });
    }

    public void paintComponent (Graphics g){
        super.paintComponent(g);



        for (Image i: images){
            i.draw(g);

        }


    }



    public void addImage(Image i){

        images.add(i);
        Graphics g = getGraphics();
        i.draw(g);

    }

    public void buttonPressed(JFileChooser fc) throws IOException {

        File selectedFile = fc.getSelectedFile();
        String filepath = String.valueOf(selectedFile.getAbsolutePath());
        Image i = new Image(x, y, filepath );
        selected = i;
        addImage(i);
        repaint();

    }

    public Image findImage(int x, int y){

        Image[] imageArray = images.toArray(new Image[images.size()]);

        for (int i = imageArray.length - 1; i >= 0; i--){
            if (imageArray[i].containsXY(x, y)){
                return imageArray[i];
            }
        }
        return null;
    }


    public void moveImage (Image i, int x, int y) { //

        i.move(getGraphics(), x, y);
    }

    public boolean removeImage(Image i){

        Graphics g = getGraphics();
        i.undraw(g, Color.WHITE);
        return images.remove(i);

    }

    @Override
    public void mouseClicked(MouseEvent e) {
        x = e.getX();
        y = e.getY();
        System.out.println("mouseclick");

        selected = findImage(x,y);

        if (selected != null) {

            Graphics g = getGraphics();

            try {
                selected.turn(g);
                repaint();
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            selected = null;
        }

    }

    @Override
    public void mousePressed(MouseEvent e) {
        Image i = findImage(e.getX(), e.getY());

        if (i == null) {

            System.out.println("null mousepress");
            return;

        }

        else {
            System.out.println("not null mousepress");
            if (i == selected){
                return;
            }
            else {
                removeImage(i);
                addImage(i);
                selected = i;

            }


        }






    }

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

        if (selected != null) {
            moveImage(selected,x,y);
            repaint();
        }
    }

    @Override
    public void mouseReleased(MouseEvent e) {
        selected = null;
    }

    @Override
    public void mouseEntered(MouseEvent e) {

    }

    @Override
    public void mouseExited(MouseEvent e) {

    }

    @Override
    public void mouseMoved(MouseEvent e) {

    }
}

Can anyone with experience in this help? I am pulling my hair with this since about a week now...

You can store two variables for x and y offset in your PaintSurface class and initilize them in the findImage() method like this:

if (imageArray[i].containsXY(x, y)){
   xOffset = x - imageArray[i].getX();
   xOffset = y - imageArray[i].getY();
   return imageArray[i];
}

Then you change your move() method in Image to

move(Graphics g, int x, int y, int xOffset, int yOffset) {
    undraw(g, Color.WHITE);
    this.x = x - xOffset;
    this.y = y - yOffset;
    draw(g);
}

You need to track the change from where you clicked instead of moving to the new cursor position. In mousePressed , store the original press location:

// lastX, lastY are object variables
lastX = e.getX();
lastY = e.getY();

In mouseDragged , calculate the delta

public void mouseDragged(MouseEvent e) {
    int x = i.getX() + e.getX() - lastX;
    int y = i.getY() + e.getY() - lastY;

    if (selected != null) {
        moveImage(selected,x,y);
        repaint();
    }
    lastX = e.getX();
    lastY = e.getY();
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM