Search code examples
javajpanelmousemotionevent

Java Dragging Drawn Balls


I have created a program which draws a circle when I click on the screen. I have it working so that I can draw as many circles as I want. I can even drag one circle and not the others if I hard code which circle I am dragging. The code is:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.util.List;
import java.util.ArrayList;

public class DrawBall extends JPanel implements MouseListener, MouseMotionListener {
private List<Ball> balls;
private int x, y;
private int numBalls = 0;
boolean drag = false;

public static void main(String[] args) {
    javax.swing.SwingUtilities.invokeLater(new Runnable() {
        public void run() {
            createAndShowGUI();
        }
    });
}

private static void createAndShowGUI() {
    JFrame frame = new JFrame("Draw Ball");
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    JComponent newContentPane = new DrawBall();
    newContentPane.setOpaque(true);
    frame.setContentPane(newContentPane);
    frame.setSize(300, 300);
    frame.setVisible(true);
}

public DrawBall() {
    super(new BorderLayout());
    balls = new ArrayList<Ball>(10);
    addMouseListener(this);
    addMouseMotionListener(this);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g.create();
    g2d.setRenderingHint(RederingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
    for(Ball ball: balls) {
        ball.paint(g2d);
    }
    g2d.dispose();
}

public void mouseClicked(MouseEvent event) {
    x = (int) event.getPoint().getX();
    y = (int) event.getPoint().getY();
    Ball ball = new Ball(Color.red, numBalls, 30);
    ball.setX(x);
    ball.setY(y);
    balls.add(ball);
    numBalls = numBalls + 1;
    repaint();
}

public void mousePressed(MouseEvent event) {
    drag = true;
}

public void mouseReleased(MouseEvent event) {
    drag = false;
}
public void mouseEntered(MouseEvent event) {}
public void mouseExited(MouseEvent event) {}

public void mouseDragged(MouseEvent event) {
    if(drag == true) {
        x = (int) event.getPoint().getX();
        y = (int) event.getPoint().getY();
        if(event.getSource() == balls.get(0)) {
            Ball ball = balls.get(0);
            ball.setX(x);
            ball.setY(y);
            balls.set(0,ball);
        }
        repaing();
    }
}

public void mouseMoved(MouseEvent event) {}

public class Ball {
    private Color color;
    private int x, y, diameter, id;

    public Ball(Color color, int id, int diameter) {
        setColor(color);
        setID(id);
        setDiameter(diameter);
    }

    public void setX(int x) {
        this.x = x;
    }

    public void setY(int y) {
        this.y = y;
    }

    public void setID(int id) {
        this.id = id;
    }

    public void setDiameter(int diameter) {
        this.diameter = diameter;
    }

    public void setColor(Color color) {
        this.color = color;
    }

    public int getX() {
        return x;
    }

    public int getY() {
        return y;
    }

    public int getID() {
        return id;
    }

    public int getDiameter() {
        return diameter;
    }

    public Color getColor() {
        return color;
    }

    protected void paint(Graphics2D g2d) {
        int x = getX();
        int y = getY();
        g2d.setColor(getColor());
        g2d.fillOval(x, y, getDiameter(), getDiameter());
    }
}
}

My question is this: In my mouseDragged method, is there an easy way to tell which circle I am hovering over? I have played around with the event.getSource() but it doesn't seem to be working for my circles, at least not in the way I would expect. Thanks for any help.


Solution

  • Modify your Ball class so it creates a circle based on the center point and the radius, rather than the upper left point and the diameter.

    Then, you can calculate if you click inside of a circle by applying the distance formula to the point you've clicked and the center point of each of the balls in turn.

    The first ball where the distance is less than the radius is the ball you've clicked on. Or, if you want to be more sophisticated, the ball with the smallest distance less than the radius is the ball you've clicked on.