0
 @Override
    public Shape getShape() {
        final Ellipse2D.Double result = new Ellipse2D.Double();
        final double px = Math.min(getStart().getX(), getEnd().getX());
        final double py = Math.min(getStart().getY(), getEnd().getY());
        final double pw = Math.abs(getStart().getX() - getEnd().getX());
        result.setFrame(px, py, pw, pw);
        return result;
    }

So this getShape() is returning the shape to a class that draws the shape. getStart() gets the starting Point of the mouse on click, and getEnd() gets the Point at mouse release. Now, when I drag to draw a circle, if i drag to the right or down the circle works as intended and expands to the mouse, if I drag up or left of the cursor the circle expands as it should BUT the circle shape moves up and down with the cursor and I am not sure why.

Jacob R
  • 327
  • 2
  • 11
  • 2
    Shapes are draw from the top/left corner to the right/down. So you need to adjust the points so the smaller represent the top left corner. While it uses a `Rectangle`, [this example](http://stackoverflow.com/questions/22645172/java-draws-rectangle-one-way-not-both/22645343#22645343) demonstrates the basic concept – MadProgrammer May 11 '17 at 01:09
  • I read through that post, but it doesn't solve the dragging expansion of the circle, and how it moves up and down. Also how can you achieve this with Rectangle2D and not just the standard Rectangle. – Jacob R May 11 '17 at 03:25
  • Instead of updating the `Rectangle` class, create a new instance of `Rectangle2D` each time you need to update it. And, the concept of calculating the min/max values will work, use it all time – MadProgrammer May 11 '17 at 03:33
  • Ya still not working as intended using the min/max values, because my Square tool is a separate class and doesn't have access to the g2d for drawing. I'm also not sure how this helps with the dragging left or down, which is moving my shape up or down with the cursor – Jacob R May 11 '17 at 17:30
  • @MadProgrammer [Image](http://i.imgur.com/vhTTlVP.gifv) This is using your code implementation with min and max, see how the circle moves up and down when draggin in certain directions? – Jacob R May 12 '17 at 19:11
  • @MadProgrammer Here is actually the direct implementation of your code using Ellipse2D. [Image](http://i.imgur.com/PcqkhU8.gifv) – Jacob R May 12 '17 at 19:42
  • Notice how the width and height change, which obviously circles don't do. Now if I change the height to match the width, [Image](http://i.imgur.com/GJ1tnpS.gifv). Btw I highly appreciate your feedback and I am just trying to figure this out, because I can't wrap my head around it. – Jacob R May 12 '17 at 19:44
  • Pw should be a product of min/max value – MadProgrammer May 12 '17 at 20:55

1 Answers1

3

Shapes in Java are based on the top/left corner as the anchor and the width/height been drawn down/right.

You need to calculate the bounding box between the click point and the drag point

public Shape getShape() {
    final Ellipse2D.Double result = new Ellipse2D.Double();
    final double px = Math.min(getStart().getX(), getEnd().getX());
    final double py = Math.min(getStart().getY(), getEnd().getY());
    final double pw = Math.abs(getStart().getX() - getEnd().getX());
    result.setFrame(px, py, pw, pw);
    return result;
}

The problem is, you're still using the difference between the click point and the drag point to calculate the width, pw should be the difference between the maxX and minX values

So this example shows you how to calculate the anchor and size properties

I read through that post, but it doesn't solve the dragging expansion of the circle, and how it moves up and down.

Then you're doing something wrong

I am trying to get a circle drawn not a circle without the same width and height(ellipse).

Okay, so it should always appear that the circle is been draw from the anchor point, so when the minX or minY is less than the clickPoint's x/y points, then you need to adjust them as a difference of the clickPoint and the size

Example

So, this will make it "appear" as if the circle is always been drawn from the intial click point

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.Shape;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Ellipse2D;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class SelectionExample {

    public static void main(String[] args) {
        new SelectionExample();
    }

    public SelectionExample() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                }

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {

        private Point clickPoint;

        private Shape shape;
        private Rectangle box;

        public TestPane() {
            MouseAdapter ma = new MouseAdapter() {

                @Override
                public void mouseDragged(MouseEvent e) {
                    int minX = Math.min(e.getX(), clickPoint.x);
                    int minY = Math.min(e.getY(), clickPoint.y);
                    int maxX = Math.max(e.getX(), clickPoint.x);
                    int maxY = Math.max(e.getY(), clickPoint.y);

                    box = new Rectangle(minX, minY, maxX - minX, maxY - minY);
                    int size = Math.min(maxX - minX, maxY - minY);
                    if (minX < clickPoint.x) {
                        minX = clickPoint.x - size;
                    }
                    if (minY < clickPoint.y) {
                        minY = clickPoint.y - size;
                    }

                    shape = new Ellipse2D.Double(minX, minY, size, size);
                    repaint();
                }

                @Override
                public void mousePressed(MouseEvent e) {
                    clickPoint = new Point(e.getPoint());
                }

            };

            addMouseListener(ma);
            addMouseMotionListener(ma);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (shape != null) {
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(new Color(0, 0, 255, 64));
                g2d.fill(shape);
                g2d.setColor(Color.BLUE);
                g2d.draw(shape);
                g2d.draw(box);
                g2d.dispose();
            }
        }
    }

}
Community
  • 1
  • 1
MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Ok so the gif you just posted, that is not a circle that is being created, that is creating an ellipse, that is why I am trying to lock the width and height to the same value. It always needs to be a circle, not an ellipse. I can get my output to look just like that GIF but I am trying to achieve that is always a circle while dragging. For example in photoshop if you hold shift while drag a circle it stays locked width and height, so they are always equal. – Jacob R May 12 '17 at 21:37
  • *"Ok so the gif you just posted, that is not a circle that is being created, that is creating an ellipse*" - So, I've demonstrated the basic requirements to demonstrate how it "could" be achieved, I'm sure you can analyze the mechanism to figure out a solution to making a circle, it would probably be something like determining which of the two `maxX`/`maxY` axis you want to use - This is all you'll be getting from me, because I've now provided you with two basic working examples, all that remains is for you to decided which axis you want to use and calculate the diameter you want to use – MadProgrammer May 12 '17 at 21:41
  • Shouldn't the minimums change based up where the cursor is, since it is using the parameters of Ellipse2D.Double(x start, y start, height, width), therefore if you drag up and to the right, it is causing the start points to be on the bottom right of shape when it should change based on what (quadrant) you are in. – Jacob R May 12 '17 at 21:41
  • Ok, well thank you for you time. I can't really mark this as an answer though, because it was not solving the problem in the first place. I never had an issue creating an ellipse and being able to drag it, I have done that already and it works great, I am trying to get a circle drawn not a circle without the same width and height(ellipse). – Jacob R May 12 '17 at 21:42
  • @ThereIsNoSpoon As I explained, this calculates the difference between the start point and the end point, creating a bounding box, this is then used to generate the shape from `min` to `max - min`, this accommodates the requirements of the shape API – MadProgrammer May 12 '17 at 21:43
  • @ThereIsNoSpoon One thing to remember about software development, you will never find the "exact" answer to your problems, you will actually have to make some effort to modify things you find/learn to solve the problems at hand, this is what will make you a better developer - just because the answer doesn't generate the "exact' result your after doesn't make it wrong - this example will allow you to generate any `Shape`, now you need to make the modifications to it to meet your needs – MadProgrammer May 12 '17 at 21:46
  • Yes, I realize this, and for some reason everything I try is just not working, I can get the ellipse to work properly but for example I tried implementing your code and then after setting the height to equal the width manually, causes the desire effect of a circle that is locked, but is still draggable up and down for some reason, which moves the shapes in an unintented direction. – Jacob R May 12 '17 at 21:50
  • Which I don't understand because I am not manipulating the y or x position values at that point. – Jacob R May 12 '17 at 21:51
  • Right - A solution might be use the click point as the center of the cirlce instead – MadProgrammer May 12 '17 at 22:00
  • Ya i tried that. Same situation, something is making the y coordinate of the circle just move whenever it wants to. I give up honestly. Thank you for your time. Didn't mean to come off rude during any part of our conversation, I am just getting a little frustrated with my code. – Jacob R May 12 '17 at 22:11
  • @ThereIsNoSpoon My brain hurts, I've updated to so that the "circle" appears to be drawn from the original click point :P – MadProgrammer May 12 '17 at 22:19