Madison
Madison

Reputation: 71

Dragging A Circle on a JFrame

I am trying to have a circle appear on the screen, then when the user clicks INSIDE the circle, enable the ability for them to drag the circle where the mouse goes while it is being pressed.

This is the code i have so far, the drag works, but it is allowing the user to drag without them pressing the inside of the circle, just when anywhere on the screen is pressed.

I hope i am not too confusing

here's the code i have, please if someone could just tell me the code that needs to be corrected, it will save me anymore hours.

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

public class DragCircle extends JFrame {
    private static final long serialVersionUID = 1L;

    public static int size = 400;

    public static int r = 10;

    private int x;

    private int y;

    private int cX;

    private int cY;

    private int dX;

    private int dY;

    private MouseHandler mh;

    boolean isCircleClicked = false;

    public static void main(String[] args) {
        DragCircle c1 = new DragCircle();
        c1.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

    }

    public DragCircle() {

        super("Drag circle");

        cX = r + 100;
        cY = r + 100;

        mh = new MouseHandler();
        addMouseListener(mh);
        addMouseMotionListener(mh);

        setSize(size, size);
        setVisible(true);

    }

    public void paint(Graphics g) {
        super.paint(g);
        g.setColor(Color.RED);
        g.fillOval(cX, cY, r * 2, r * 2);

    }

    private class MouseHandler extends MouseAdapter implements
            MouseMotionListener {
        public void mousePressed(MouseEvent me)

        {

            if ((cX - me.getX()) * (cX - me.getX()) + (cY - me.getY())
                    * (cY - me.getY()) < r * r) {
                isCircleClicked = true;
            }
        }

        public void mouseDragged(MouseEvent me) {
            if (isCircleClicked) {

                x = me.getX() - dX;
                y = me.getY() - dY;
                cX = x + r;
                cY = y + r;
                repaint();
            }
        }

        public void mouseReleased(MouseEvent e) {
            isCircleClicked = false;
        }

    }

}

Upvotes: 0

Views: 5266

Answers (2)

Joey
Joey

Reputation: 354526

Your one problem is with

public void mouseDragged(MouseEvent me) {
    if (isCircleClicked = true) {

What you're doing here is setting isCircleClicked to true every time you drag the mouse. Also this statement evaluates to true which is why you can drag anywhere and move the circle. Change this to

 if (isCircleClicked) {

and you should be fine here.

The next problem is that you never reset isCircleClicked to false. You should be doing this either in mouseReleased or change your mousePressed as follows:

public void mousePressed(MouseEvent me) {
    isCircleClicked =
        (cX - me.getX()) * (cX - me.getX()) +
        (cY - me.getY)) * (cY - me.getY()) < r * r;
}

which will set isCircleClicked accordingly.

There is still something to do, though. In the current form you need to start dragging to the upper-left of the center point, as illustrated below:

+------+
|      |
|    .-|-.
|   /  |  \
+------+  |
    \     /
     '-_-'

This is because of your drawing: fillOval takes an upper-left corner of the oval and a width and height of the bounding rectangle. It's not the center point and the respective diameters. Hence you need to adapt his as follows:

g.fillOval(cX - r, cY - r, r * 2, r * 2);

Note the offset by the radius to the left and top.

Furthermore, your dragging code needs a bit more work. You are currently assuming that the user drags the circle's center. What you need to do is save the coordinates of the mouse click and then move the circle based on the mouse's movement relative to the last point. Currently you're moving relative to the circle's center so for the movement to be nice you have to start dragging exactly in the center of the circle. I'll leave that as an exercise for you :-)

Besides, your listener class already inherits from MouseAdapter so you don't need to explicitly implement the MouseMotionListener since MouseAdapter implements it already.

Upvotes: 2

camickr
camickr

Reputation: 324118

The structure of you program is wrong. You should never override the paint(...) method of a JFrame. That is an old AWT trick and should NOT be used with Swing.

Read the section from the Swing tutorial on Custom Painting for an example of the proper way to do painting. The basics are to override the paintComponent(...) method of a JPanel and then add the panel to the content pane of the frame.

With regards to you question a better solution is to create an Elllipse2D object to represent your circle. Then the custom painting can use the drawShape(...) method of the Graphics2D class. Then in you MouseListener code you can use the Shape.contains(...) method to see if the mouse was clicked on the circle.

Upvotes: 0

Related Questions