I am creating a simple game where a person clicks on an image the score increases by one. It seems simple enough, right? Here's the catch-- the images will be hidden partially behind other images!
Currently, I'm using several imageIcons to set up my scene. For instance, my foreground has an image "foreground.png," my background is "background.png", and my image that is hiding between the two is "hiding.png".
My first thought was to simply get the coordinates of the imageIcon hiding, add the height() and width() to them, and create a mouse listener that would only work in that specified region. However, that would give me a rectangle for the user to click which would defeat the purpose of hiding the object (someone could click the rigid boundary of the graphic behind the foreground).
Do you have any suggestions on how to make a mouse action listener work only on the VISIBLE pixels of an imageIcon? Yes, I understand that action listeners can only be applied to components (such as buttons) but "the button" just doesn't do what I want for this project.
Example 1
This basically uses a series of JLabel
s on a JLayeredPane
. Each label has it's own mouse listener and when you mouse over it, will turn red. But, if there is a label above it, it won't respond to mouse events...

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import javax.imageio.ImageIO;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ClickMyImages {
public static void main(String[] args) {
new ClickMyImages();
}
public ClickMyImages() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JLayeredPane {
public TestPane() {
try {
BufferedImage img1 = ImageIO.read("/Image1");
BufferedImage img2 = ImageIO.read("/Image2");
BufferedImage img3 = ImageIO.read("/Image3");
BufferedImage img4 = ImageIO.read("/Image4");
BufferedImage img5 = ImageIO.read("/Image5");
JLabel label1 = new ClickableLabel(new ImageIcon(img1));
JLabel label2 = new ClickableLabel(new ImageIcon(img2));
JLabel label3 = new ClickableLabel(new ImageIcon(img3));
JLabel label4 = new ClickableLabel(new ImageIcon(img4));
JLabel label5 = new ClickableLabel(new ImageIcon(img5));
Dimension masterSize = getPreferredSize();
Dimension size = label1.getPreferredSize();
label1.setBounds((masterSize.width - size.width) / 2, (masterSize.height - size.height) / 2, size.width, size.height);
Point masterPoint = label1.getLocation();
size = label2.getPreferredSize();
label2.setBounds(
masterPoint.x - (size.width / 2),
masterPoint.y - (size.height / 2),
size.width, size.height);
size = label3.getPreferredSize();
label3.setBounds(
masterPoint.x + (size.width / 2),
masterPoint.y - (size.height / 2),
size.width, size.height);
size = label4.getPreferredSize();
label4.setBounds(
masterPoint.x - (size.width / 2),
masterPoint.y + (size.height / 2),
size.width, size.height);
size = label5.getPreferredSize();
label5.setBounds(
masterPoint.x + (size.width / 2),
masterPoint.y + (size.height / 2),
size.width, size.height);
add(label1);
add(label2);
add(label3);
add(label4);
add(label5);
} catch (Exception e) {
e.printStackTrace();
}
}
@Override
public Dimension getPreferredSize() {
return new Dimension(800, 800);
}
}
// This is for demonstration purposes only!
public class ClickableLabel extends JLabel {
private boolean isIn = false;
public ClickableLabel(Icon image) {
super(image);
addMouseListener(new MouseAdapter() {
@Override
public void mouseEntered(MouseEvent e) {
isIn = true;
repaint();
}
@Override
public void mouseExited(MouseEvent e) {
isIn = false;
repaint();
}
});
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
if (isIn) {
Graphics2D g2d = (Graphics2D) g.create();
g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
g2d.setColor(Color.RED);
g2d.fillRect(0, 0, getWidth(), getHeight());
g2d.dispose();
}
}
}
}
Example 2
This examples uses the paintComponent
method to renderer the images. It checks the pixel alpha of the image at the mouse point to determine if the mouse event should fall through or not.
I've been a little strict using an alpha value of 255
, but you could soften it a little based on your needs (something like 225 instead for example)...
I've hard coded the layers so that the tree is always above the squirrel, but it wouldn't be hard to add all the images to List
in the order you want them to appear and simple run down the list till you get a hit.

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Composite;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Rectangle;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
public class ClickMyDrawnImages {
public static void main(String[] args) {
new ClickMyDrawnImages();
}
public ClickMyDrawnImages() {
EventQueue.invokeLater(new Runnable() {
@Override
public void run() {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
}
JFrame frame = new JFrame("Testing");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setLayout(new BorderLayout());
frame.add(new TestPane());
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);
}
});
}
public class TestPane extends JPanel {
private BufferedImage tree;
private BufferedImage squirrel;
private BufferedImage mouseOver;
public TestPane() {
try {
tree = ImageIO.read(new File("Tree.png"));
squirrel = ImageIO.read(new File("Squirrel.png"));
} catch (IOException exp) {
exp.printStackTrace();
}
addMouseMotionListener(new MouseAdapter() {
@Override
public void mouseMoved(MouseEvent e) {
if (withinTree(e.getPoint())) {
mouseOver = tree;
} else if (withinSquirrel(e.getPoint())) {
mouseOver = squirrel;
} else {
mouseOver = null;
}
repaint();
}
});
}
@Override
public Dimension getPreferredSize() {
return new Dimension(200, 200);
}
protected boolean withinTree(Point p) {
return withinBounds(p, getTreeBounds(), tree);
}
protected boolean withinSquirrel(Point p) {
return !withinBounds(p, getTreeBounds(), tree) && withinBounds(p, getSquirrelBounds(), squirrel);
}
protected Rectangle getTreeBounds() {
int width = getWidth();
int height = getHeight();
int x = (width - tree.getWidth()) / 2;
int y = (height - tree.getHeight()) / 2;
return new Rectangle(x, y, tree.getWidth(), tree.getHeight());
}
protected Rectangle getSquirrelBounds() {
Rectangle bounds = getTreeBounds();
return new Rectangle(
bounds.x - (squirrel.getWidth() / 4),
(getHeight() - squirrel.getHeight()) / 2,
squirrel.getWidth(), squirrel.getHeight());
}
@Override
protected void paintComponent(Graphics g) {
super.paintComponent(g);
Graphics2D g2d = (Graphics2D) g.create();
int width = getWidth();
int height = getHeight();
int x = (width - tree.getWidth()) / 2;
int y = (height - tree.getHeight()) / 2;
g.drawImage(highlight(squirrel), x - (squirrel.getWidth() / 4), (height - squirrel.getHeight()) / 2, this);
g2d.drawImage(highlight(tree), x, y, this);
g2d.dispose();
}
protected BufferedImage highlight(BufferedImage img) {
BufferedImage highlight = img;
if (img.equals(mouseOver)) {
highlight = new BufferedImage(img.getWidth(), img.getHeight(), BufferedImage.TYPE_INT_ARGB);
Graphics2D g2d = highlight.createGraphics();
g2d.setColor(Color.RED);
g2d.drawImage(img, 0, 0, this);
g2d.setComposite(AlphaComposite.SrcAtop.derive(0.5f));
g2d.fillRect(0, 0, highlight.getWidth(), highlight.getHeight());
g2d.dispose();
}
return highlight;
}
protected boolean withinBounds(Point p, Rectangle bounds, BufferedImage image) {
boolean withinBounds = false;
if (bounds.contains(p)) {
int x = p.x - bounds.x;
int y = p.y - bounds.y;
int pixel = image.getRGB(x, y);
int a = (pixel >> 24) & 0xFF;
// could use a little weighting, so translucent pixels can be effected
if (a == 255) {
withinBounds = true;
}
}
return withinBounds;
}
}
}
来源:https://stackoverflow.com/questions/15871530/java-imageicons-and-actioin-listeners