简体   繁体   中英

How to make a shape move to click in JPanel?

I am trying to make to make a shape move to wherever I click my mouse. I got the shape to move, and it moves towards the general direction of where I clicked, but it never moves exactly to where I clicked, it misses by a good distance. Since it doesn't move exactly to where I clicked, the shape continues to move and doesn't stop.

Here is the code:

import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.awt.event.MouseListener;
import java.io.IOException;

public class GraphicsTester extends JFrame implements MouseListener {
    private int startX;
    private int startY;
    private int endX;
    private int endY;
    private int stepX;
    private int stepY;
    private Timer sliderTimer = new Timer(40, new SlideListener());

    public GraphicsTester() throws IOException {
        setTitle("Graphics Tester 1");
        setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
        setLayout(new BorderLayout());

        JPanel basePanel = new JPanel(new BorderLayout()) {
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g;
                g2d.setColor(Color.red);
                g2d.fillOval(215 + stepX, 215 + stepY, 30, 30);
                startX = stepX;
                startY = stepY;
                if (215 + stepX == endX && 215 + stepY == endY) {
                    sliderTimer.stop();
                }
            }
        };
        basePanel.setPreferredSize(new Dimension(500, 500));
        basePanel.addMouseListener(this);

        getContentPane().add(basePanel);
        pack();
        setVisible(true);
    }
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    new GraphicsTester();
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
            }
        });
    }

    @Override
    public void mouseClicked(MouseEvent e) {
    }

    @Override
    public void mousePressed(MouseEvent e) {
        endX = e.getX();
        endY = e.getY();
        System.out.println("endX: " + endX + ", endY: " + endY);
        sliderTimer.start();
    }

    @Override
    public void mouseReleased(MouseEvent e) {
    }

    @Override
    public void mouseEntered(MouseEvent e) {
    }

    @Override
    public void mouseExited(MouseEvent e) {
    }

    private class SlideListener implements ActionListener {
        @Override
        public void actionPerformed(ActionEvent e) {
            stepX += (endX - startX) / 5; // the 5's are just arbitrary values, I chose 5 because it makes the shape slide at the speed I want
            stepY += (endY - startY) / 5;
            System.out.println("stepX: " + (215 + stepX) + ", stepY: " + (215 + stepY));
            repaint();
        }
    }
}

How can I make the shape move to exactly where I clicked? The problem lies with stepX += (endX - startX) / 5; and stepY += (endY - startY) / 5; . Those two lines are causing the shape not to move exactly to where I clicked, since they don't increment stepX and stepY precisely to the click and instead "round" at each increment. I don't know how to fix these two lines so that they increment stepX and stepY exactly to where I clicked and therefore stop moving the shape once it reaches endX and endY .

Your main problem is that you add 215 to stepX and stepY in your paintComponent() method, which is why it appears to be 'way off'. This is because it draws at stepX + 215 and stepY + 215 , when you really want it drawn at exactly stepX and stepY (which are based on the mouse pointer at the time of clicking). Presumably the + 215 is just an offset for the initial location?

Simple fix is to change your paintComponent() method to:

protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g2d.setColor(Color.RED);
    g2d.fillOval(stepX, stepY, 30, 30);
    startX = stepX;
    startY = stepY;
    if (stepX == endX && stepY == endY) {
        sliderTimer.stop();
    }
}

or just be consistent with the offset of all the coordinates.

Secondly, your slideTimer.stop() is highly unlikely to ever be called. You should set stepX = endX and stepY = endY if the following is true: end - step < 5 , ie

stepX = endX - startX < 5 ? endX : stepX + (endX - startX) / 5;
stepY = endY - startY < 5 ? endY : stepY + (endY - startY) / 5;

This may not bring it to the nicest possible finish, so feel free to experiment.

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