views:

79

answers:

1

A week into it, and I am just banging my head up against this problem. It should be a simple excersise:

I have a rectangle. I click and drag the rectangle on an x axis. The rectangle should only move within a set bounding area (the canvas), so if the canvas is 200 px wide, then the x coordinate should only go from 0 to getWidth()-RECTANGLE_WIDTH.

Simple enough, but I just can not get the darn thing to work.

Below is my unwieldy code.

I have attached two GLabels to view coordinates. I noticed that the mouseMoved label will only display coordinates within the canvas (what I want), but the mouseDragged label will go negative, and will also show coordinates beyond the canvas-this is also where the rectangle object movement is being controlled. Im'm not sure why those two behaviors are different.

Right now, my statement below:

if ((gobj.getX()) > 0 && (gobj.getX()) < (APPLICATION_WIDTH - PADDLE_WIDTH)){
                gobj.move(e.getX() - lastX, 0);

               } 

what that statement does so far is get the rectangle to the edge, but then it just sticks there and won't return. I'm pulling my hair out on this thing...

import java.awt.*;
import java.awt.event.*;
import acm.graphics.*;
import acm.program.*;

/** This class displays a mouse-draggable rectangle and oval */

public class DragObject extends GraphicsProgram {

private static final int PADDLE_WIDTH = 150;
public static final int APPLICATION_WIDTH = 700;

    public void run() {

        GRect rect = new GRect(100, 100, 150, 100);
        rect.setFilled(true);
        rect.setColor(Color.RED);   
        add(rect);

        label2 = new GLabel ("");
        add(label2, 300, 400);


        label = new GLabel ("");
        add(label, 300, 300);
        addMouseListeners();


    }

    /* these coordinates are never going beyond the canvas-even if the 
     * mouse does...this is good...i want this   */

    public void mouseMoved(MouseEvent e){

        label2.setLabel("Coordinates:" + e.getX() + ", " + e.getY());

    }

/** Called on mouse press to record the coordinates of the click */
    public void mousePressed(MouseEvent e) {
        lastX = e.getX();
        lastY = e.getY();
        gobj = getElementAt(lastX, lastY);

    }

/** Called on mouse drag to reposition the object */
    public void mouseDragged(MouseEvent e) { 

          if ((gobj.getX()) > 0 && (gobj.getX()) < (APPLICATION_WIDTH - PADDLE_WIDTH)){
            gobj.move(e.getX() - lastX, 0);

           } 

            lastX = e.getX();


            /* This label is active when i click the object, and does go into negative 
             * numbers and still counts even when off the canvas...*/
            label.setLabel("Coordinates:" + e.getX() + ", " + e.getY());
    }

/* Instance variables */

private GLabel label2;
private GLabel label;
private GObject gobj;   /* The object being dragged */
private double lastX;   /* The last mouse X position */
private double lastY;   /* The last mouse Y position */
}
+2  A: 

You can drag out of a component, even out of a window, quite by design in order to support drag and drop.

For drag events you just have to constrain the event location to within it's container:

static public final int MAX_X=(CANVAS_WIDTH - PADDLE_WIDTH);

...

public void mouseDragged(MouseEvent e) { 
    int px=Math.max(0,Math.min(e.getX(),MAX_X));
    int dx=(px-lastX);

    if(dx!=0) { 
        gobj.move(dx); 
        lastX=px;
        }
    }

After sleeping on it, and re-reading the comments, I have an idea where the problem might lie - in the code provided GObject is not shown, nor is how it's created/initialized. So it's hard to guess at the context for the code in the question.

I would wager that the paddle is created to be initially in the middle (perhaps middle/bottom) of the canvas. The code above, and in the question, only constrains a delta to prevent the delta from exceeding the bounds of the canvas - it does not account for the initial position of the paddle. That is, if the paddle starts out at x=350, and the delta allows for a total of 700-150=550, then the constrained delta will allow the paddle to move to 350-550=-200, the paddle will move to 200 pixels beyond the left edge.

So you need to pass the move method the upper bounds and constrain the resulting position to 0 <= px <= UPPER... something like:

    ...
    if(dx!=0) { 
        gobj.moveX(dx,MAX_X); 
        lastX=px;
        }
    ...

GObject:

public void moveX(int dlt, int max) {
    positionX=Util.limitInt((positionX+dlt),0,max);
    }

Util:

/**
 * Limit the range of a number to the specified values.
 */
static public int limitInt(int val, int low, int hgh) {
    return ((val<low) ? low : ((val<hgh) ? val : hgh));
    }

And I would repeat all the code for Y, and manipulate this axis separately. Otherwise you will need to extend your move method to:

public void move(int dltX, int maxX, int dltY, int maxY) {
    positionX=Util.limitInt((positionX+dltX),0,maxX);
    positionY=Util.limitInt((positionX+dltY),0,maxY);
    }
Software Monkey
ok. That makes sense about the drag and drop, but how how how do I constrain the event location? That is what's driving me nuts.
Joel
@Joel: Updated my answer.
Software Monkey
Well-That doesn't do what is expected. Moving the mouse left moves the rectangle right, and vice versa. Also though it stops at the bounding box, if I reclick and drag again, the rectangle moves off the screen...
Joel
Changing this line: int dx=(px - lastX); fixed the inversion, but I'm still not consistently only hitting the bounding box edge...I get out of the box if I move the mouse around and release the button sometimes, etc.
Joel
@Joel: Also dump dx and px and see if they do anything unexpected.
Software Monkey
sorry-what do you mean dump them?
Joel
@Joel: Print them in a label as you are doing for the event coordinates.
Software Monkey
It's doing what it was before-going negative below 0 and going past the canvas to the right. Also, to the left, the rectangle does not stop when it's x coordinate reaches 0, but rather when the mouse reaches 0...
Joel
PX: is giving us a steady 0-550 when scrolling from left to right. Stops at 550 even if I go past the canvas. DX is fluctuationg between 0 and -1 when moved slowly. If I move the mouse fast, that number jumps, but gets back to -1. It becomes 0 at the edges of the canvas.
Joel
@Joel: That is the expected behavior, assuming when you are outside of the canvas dx is always zero; perhaps the problem is in your gobj.move() method.
Software Monkey
What I need to do is know how to compare the gobj.getX(); value and make sure that never goes less than 0 or more than MAX_X. Right now we are looking at the e.getX().
Joel
PS: I did change the move method too because it needed to contain the y: gobj.move(dx, 0);
Joel
@Joel: Why not just constrain it's setter/move? It seems wrong to change the getter to "lie", when the setter should prevent what is an invalid value to begin with.
Software Monkey
man-I'm still a newbie at this, so not sure what you mean? :-( Can you show me an example?
Joel
@Joel: I extended my answer further; hope it helps.
Software Monkey
just saw this-going to bed now, but I'll take a look at it in the morning. Thanks!
Joel