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.