0

I am working with images only and the dimensions of the window that I am using to view my application may be different on different systems. I have a mouse action listener that is listening for clicks on the main view of my program. I have a rounded rectangle that looks like a button. I want to make it so that way the mouse action listener only listens to the area of the rounded rectangle rather than the entire image on all systems. Like the title says, not the entire image has content, in particular, the corners don't look like they are part of the image, so I don't want to allow the user to be able to click on parts of the image without content and get the same result as if they clicked on the part with content. My image looks similar to this image
(source: youthedesigner.com)

So I only want the program to do something if the user clicks on the button inside the image rather than the nice stuff around the button. This is what I have right now to listen to clicks:

@Override
public void mouseClicked(MouseEvent e) {
    for(int i = 0; i <= 200; i++) {
        if(e.getY() >= 100+i && e.getY() <= 300) {
            if(e.getX() >= 10+100-Math.pow(10000-(Math.pow((i-100),2.0)),.5)) && e.getX() <= 10+400-Math.pow(10000-(Math.pow((i-100),2.0)),.5))) {
                // do stuff
                i = 201;
            }
        }
    }
}

The math equation I am using in my code looks like 110-(10000-(y-100)^2)^(1/2)), which, if graphed, would look like an open parenthesis, and 410+(10000-(y-100)^2)^(1/2)), which would look like a close parenthesis 400 units away from the first graph.

The code works fine on my system, but on other systems, it doesn't work at all and I am curious how I could move the location I am listening to to correspond to how the image is scaled.

Thank you very much for any help you can provide.

Community
  • 1
  • 1
Pillager225
  • 439
  • 1
  • 3
  • 15

3 Answers3

1

The for-loop is superfluous.

You could ensure that pixels outside the button (.png) have some transparency, and then check for the alpha color component.

In this case you could add a Rect and look for that:

private boolean insideButton(Rectangle buttonRect, Point mousePt) {
    if (buttonRect.contains(mousePt)) {
        int r = buttonRect.height() / 2;
        if (mousePt.x < r) {
            // Left circle with O at (r, r)
            int xFromO = r - mousePt.x;
            int yFromO = r - mousePt.y;
            if (xFromO * xFromO + yFromO * yFromO > r * r) {
                return false; // Outside circle
            }
        }
        if (mousePt.x > buttonRect.right - r) {
            // Right circle:
            ...
        }
        return true;
    }
    return false;
}
Joop Eggen
  • 107,315
  • 7
  • 83
  • 138
0

I can think of at least two ways.

The first is to produce a mask image (black and white), where (for example) white would indicate the clickable area. Basically, you could compare the pixel color of the mask based in click pick point of the original image.

The other way would be to build a image map, basically using something like a Shape API to allow for non-rectangular shapes. This would allow to use Shape#contains to determine if the mouse clicked inside it or not

In either case, you need to take into account the x/y position of the original image

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
0

So, I used Joop's answer to solve my problem. His answer wasn't quite what I was looking for, but it gave me the idea I needed to solve my problem. The solution I came to was:

private boolean insideButton(Rectangle buttonRect, Point mousePt) {
    if (buttonRect.contains(mousePt)) {
        int r = (int)buttonRect.getHeight()/2; // radius of either of the circles that make up the sides of the rectangle
        if(mousePt.x <= buttonRect.getWidth()/2) { // if it is on the left of the button
            Point center = new Point((int)buttonRect.getX()+r, (int)buttonRect.getY()+r); // the center of the circle on the left
            double lengthToPoint = Math.pow(Math.pow(mousePt.x-center.x, 2)+Math.pow(mousePt.y-center.y, 2), 1.0/2); // length from center to the point that the user clicked at
            if(lengthToPoint > r && mousePt.x < center.x) { // if it is to the left of the center and out of the circle
                return false;
            } else {
                return true;
            }
        } else { // if it is on the right, the rest of the code is just about the same as the left circle
            Point center = new Point((int)buttonRect.getWidth()-r, (int)buttonRect.getY()+r);
            double lengthToPoint = Math.pow(Math.pow(mousePt.x-center.x, 2)+Math.pow(mousePt.y-center.y, 2), 1.0/2);
            if(lengthToPoint > r && mousePt.x > center.x) {
                return false;
            } else {
                return true;
            }
        }
    } else {
        return false;
    }
}

I know it is goes a little overboard with calculations and inefficient, but I wanted to present it this way to show a better idea of how my solution works.

Pillager225
  • 439
  • 1
  • 3
  • 15
  • Isn't it a rectangle with two circles at the left and right? My version uses like your version the containing rect, but then I check `(|` and `|)`: mouse x < r (left) or mouse x > width - r (right). Happy that you succeeded and thanks for the feedback. – Joop Eggen Nov 23 '12 at 10:07
  • Maybe, but when I used your code, it didn't work, and I had difficulty figuring out how I could tweak it to suit my need, but it gave me this idea of how to do it. – Pillager225 Dec 10 '12 at 02:16