Java ImageIcons и прослушиватели действий

Я создаю простую игру, в которой человек нажимает на изображение, и счет увеличивается на единицу. Это кажется достаточно простым, не так ли? Вот в чем загвоздка: изображения будут частично скрыты за другими изображениями!

В настоящее время я использую несколько изображений для настройки своей сцены. Например, мой передний план имеет изображение «foreground.png», мой фон — «background.png», а мое изображение, скрывающееся между ними, — «hiding.png».

Моя первая мысль состояла в том, чтобы просто получить координаты скрытия imageIcon, добавить к ним height() и width() и создать прослушиватель мыши, который будет работать только в указанной области. Однако это дало бы мне прямоугольник, по которому пользователь мог бы щелкнуть, что лишило бы цели скрытия объекта (кто-то мог щелкнуть жесткую границу изображения за передним планом).

Есть ли у вас какие-либо предложения о том, как заставить прослушиватель действий мыши работать только с ВИДИМЫМИ пикселями imageIcon? Да, я понимаю, что прослушиватели действий могут применяться только к компонентам (таким как кнопки), но " кнопка» просто не делает то, что я хочу для этого проекта.


person JavaJew22    schedule 08.04.2013    source источник
comment
Это зависит от того, как вы визуализируете изображения. Если вы используете JLabel, вы можете прикрепить прослушиватель мыши к JLabel, основываясь на Z-порядке макета компонента, вы сможете щелкнуть только видимую область метки (так как та, что над ней, будет использовать ее)   -  person MadProgrammer    schedule 08.04.2013
comment
Могу ли я рисовать JLabels за изображениями (я переопределяю paintComponent(), чтобы рисовать передний план и фон)?   -  person JavaJew22    schedule 08.04.2013
comment
Вы заботитесь о прозрачности?   -  person MadProgrammer    schedule 08.04.2013
comment
Да, но если непрозрачный метод может указать мне правильное направление, я посмотрю на него :)   -  person JavaJew22    schedule 08.04.2013


Ответы (1)


Пример 1

Это в основном использует серию JLabels на JLayeredPane. У каждой метки есть собственный прослушиватель мыши, и когда вы наводите на нее курсор, она становится красной. Но если над ним есть метка, он не будет реагировать на события мыши...

введите здесь описание изображения

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();
            }
        }
    }
}

Пример 2

В этом примере используется метод paintComponent для рендеринга изображений. Он проверяет альфа-пиксель изображения в точке мыши, чтобы определить, должно ли событие мыши пройти или нет.

Я был немного строгим, используя альфа-значение 255, но вы можете немного смягчить его в зависимости от ваших потребностей (например, что-то вроде 225)...

Я жестко закодировал слои так, что дерево всегда находится над белкой, но было бы нетрудно добавить все изображения в List в том порядке, в котором вы хотите, чтобы они отображались, и просто прокручивать список до тех пор, пока не получите результат. .

введите здесь описание изображения

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;
        }
    }
}
person MadProgrammer    schedule 08.04.2013
comment
Большое спасибо! именно это и хотел сделать - person JavaJew22; 08.04.2013
comment
@JavaJew22 JavaJew22 Я обновил, чтобы включить собственный пример рисования. - person MadProgrammer; 08.04.2013