Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can i create a complex Button shape?

I have a frame with an image covering it, And i want that every time some one clicks on a different object in the image , it will act as a button and do something.
The problem is , Is that those objects are not simple shapes, so i was thinking about drawing my own invisible buttons in the shape of those objects.

Is that possible? or what would be a better way to accomplish such a thing?

-thank you

like image 386
Dani Gilboa Avatar asked Aug 08 '13 16:08

Dani Gilboa


2 Answers

Concept: invisible buttons with circular and polygonal dispatch areas

First, you'll want a class defining an invisible button, extending javax.swing.AbstractButton so that it's still a fully functional button that you can add listeners to.

public abstract class InvisibleButton extends AbstractButton {

    public abstract boolean contains(Point point);

    @Override
    public boolean isVisible() {
        return false;
    }
}

Then, of course, you'll want implementations of that class. Here's two examples: one using a polygon for complex shapes, one using a circle.

public class PolygonalButton extends InvisibleButton {

    private Polygon area = null;

    public PolygonalButton(Polygon area) {
        this.area = area;
    }

    @Override
    public boolean contains(Point point) {
        return area.contains(point);
    }
}

public class CircularButton extends InvisibleButton {

    private int x;
    private int y;
    private double radius;

    public CircularButton(int x, int y, double radius) {
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    @Override
    public boolean contains(Point point) {
        double dx = x - point.x;
        double dy = y - point.y;
        return Math.sqrt(dx * dx + dy * dy) <= radius;
    }
}

Finally, you'll need to implement a container that handles all of these buttons, but you should use a panel instead of a frame. Rather than hook each individual listener, you can simply override the frame's event processors and pass them to the necessary buttons.

public class InvisibleButtonImagePanel extends JPanel {

    private BufferedImage image = null;
    private List<InvisibleButton> buttons = new ArrayList<>();

    public InvisibleButtonImagePanel(BufferedImage image) {
        this.image = image;
    }

    public void add(InvisibleButton button) {
        buttons.add(button);
    }

    public void remove(InvisibleButton button) {
        buttons.remove(button);
    }

    @Override
    public Dimension getPreferredSize() {
        return new Dimension(image.getWidth(), image.getHeight());
    }

    @Override
    public void processKeyEvent(KeyEvent event) {
        for (InvisibleButton button : buttons) {
            if (button.isFocusOwner()) {
                button.dispatchEvent(event);
            }
        }
        super.processKeyEvent(event);
    }

    @Override
    public void processMouseEvent(MouseEvent event) {
        for (InvisibleButton button : buttons) {
            if (button.contains(event.getPoint())) {
                button.dispatchEvent(event);
            }
        }
        super.processMouseEvent(event);
    }

    @Override
    protected void paintComponent(Graphics g) {
        g.drawImage(image, 0, 0, null);
        super.paintComponent(g);
    }
}

You'll probably want to rename the panel to something less bulky, and maybe implement your own advanced image code, but that's the basic idea behind it.

like image 168
FThompson Avatar answered Sep 21 '22 01:09

FThompson


Can you track the users mouse position via Coordinates?

 PointerInfo a = MouseInfo.getPointerInfo();
        Point b  = a.getLocation();
        int x = (int)b.getX();
        int y = (int)b.getY();

Now put a ActionPerformed Method and test if x and y = e.g. 200, 300 do this. That way when a user clicks on a spot (your aiming for area) it will redirect him to a method.

like image 36
Jebathon Avatar answered Sep 22 '22 01:09

Jebathon