s d
s d

Reputation: 311

MouseEvent getX and getY offset from actual coordinate

I'm coding a basic paint program and I have been having trouble with Rectangle and Ellipse tools. If you click and drag you should be able to draw the shape with the dimensions based on the startpoint and endpoint (both use getX() and getY()), the problem being that these two shapes get the startpoint right but the endpoint is offset in both the x and y coordinates.

This code below is pretty much the same as the code that I used in my line tool (which works properly) except swapping Line2D with Rectangle2D and Ellipse2D respectively.

package tools;

import gui.DrawingPanel;

import java.awt.event.ActionEvent;

import java.awt.event.KeyEvent;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.geom.Rectangle2D;

import javax.swing.AbstractAction;
import javax.swing.Action;
import javax.swing.ImageIcon;


/**
 * Creates the Rectangle Action.
 *@version 1
 */
public class RectangleAction extends AbstractAction {

    private final DrawingPanel myPanel;

    private Rectangle2D.Double myRectangle;
    private double Start_X;
    private double Start_Y;

    /**
     * Constructor for Rectangle Action.
     */
    public RectangleAction(final DrawingPanel thePanel) {
        super("Rectangle", getImageIcon()); 

        myPanel = thePanel;
        putValue(Action.MNEMONIC_KEY, KeyEvent.VK_R);
        putValue(Action.SELECTED_KEY, true);
    }

    @Override
    public void actionPerformed(final ActionEvent theEvent) {

        myPanel.addMouseListener(new MyMouseListener());
        myPanel.addMouseMotionListener(new MyMouseListener());

    }

    /**
     * gets the image icon of the action.
     * @return the image icon.
     */
    public static ImageIcon getImageIcon() {
        return new ImageIcon("./images/rectangle.gif");
    }    


    /**
     * Listens for mouse clicks, to draw on our panel.
     */
    private class MyMouseListener extends MouseAdapter {


        private double myX2;
        private double myY2;               


        /**
         * Handles a click event.
         * 
         * @param theEvent The event.
         */
        @Override
        public void mousePressed(final MouseEvent theEvent) {


            Start_X = (double) theEvent.getX();
            Start_Y = (double) theEvent.getY();
        }

        /**
         * Handles the release event.
         * 
         * @param theEvent The event.
         */
        @Override
        public void mouseReleased(final MouseEvent theEvent) {

            myX2 = (double) theEvent.getX();
            myY2 = (double) theEvent.getY();

            myRectangle = new Rectangle2D.Double(Start_X, Start_Y, myX2, myY2);

            myPanel.setShape(myRectangle);
            myPanel.repaint();           

        }

        /**
         * Handles a click event.
         * 
         * @param theEvent The event.
         */
        @Override
        public void mouseDragged(final MouseEvent theEvent) {

            myX2 = (double) theEvent.getX();
            myY2 = (double) theEvent.getY();

            myRectangle = new Rectangle2D.Double(Start_X, Start_Y, myX2, myY2);                                                                                          

            myPanel.setShape(myRectangle);
            myPanel.repaint();           

        }

    }

}

enter image description here

I should note that I did look at this similar question but it didn't give me the answer I was looking for; also the DrawingPanel is just a JPanel with a Paint Component to draw the shape and nothing else.

Upvotes: 2

Views: 1629

Answers (2)

user5182794
user5182794

Reputation:

You're initializing the rectangle with the x and y of release instead of width and height.

Replace

myRectangle = new Rectangle2D.Double(Start_X, Start_Y, myX2, myY2);

with

        int x;
        int y;
        if (Start_X > myX2) {
            x = myX2;
        } else {
            x = Start_X;
        }
        if (Start_Y > myY2) {
            y = myY2;
        } else {
            y = Start_Y;
        }
        myRectangle = new Rectangle2D.Double(x, y, Math.abs(myX2 - Start_X), Math.abs(myY2 - Start_Y));

Upvotes: 3

camickr
camickr

Reputation: 324118

myRectangle = new Rectangle2D.Double(Start_X, Start_Y, myX2, myY2);

The parameters are (x, y, width, height) you are trying to specify two points.

Your painting logic assumes you always drag the mouse from top/left to bottom/right. It is always possible the mouse could be dragged up and left which would result in negative values when you calculate the width/height based on the two points.

This is code I have used to calculate the Rectangle bounds correctly:

int x = Math.min(startPoint.x, e.getX());
int y = Math.min(startPoint.y, e.getY());
int width = Math.abs(startPoint.x - e.getX());
int height = Math.abs(startPoint.y - e.getY());

You don't need to create two listeners, you can just share the same listener:

//myPanel.addMouseListener(new MyMouseListener());
//myPanel.addMouseMotionListener(new MyMouseListener());
MouseAdapter myMouseAdapter = new MyMouseListener();
myPanel.addMouseListener( myMouseAdapter );
myPanel.addMouseMotionListener( myMouseAdapter);

Also, you keep adding the adapter to the panel every time you click on the button. So if you click on you line tool, then the ellispse tool and then the rectangle tool you will have 3 listener added to the panel. I would suggest you should remove all listeners from the panel before adding your listener for the current tool.

Upvotes: 4

Related Questions