Search code examples
javaswingjbuttonpaintcomponent

Event detection on opaque pixels in JButton


I have a class extending JButton that I am trying to apply a .png image to. The image is irregular in shape, and is surrounded by transparent pixels. I have overridden the paintComponent() method in the JButton to apply my buffered image to the button. Right now, the image is the only thing being drawn, which is what I want.

However, the button is still detecting events in the rectangle around it. Is there a way to limit detection to only the area containing opaque pixels (or rather to not detect events on the transparent pixels)?

Code for button class is below.

public class DrawButton extends JButton{

    private BufferedImage bi;

    public DrawButton(BufferedImage bi){
        setPreferredSize(new Dimension(bi.getWidth(), bi.getHeight()));
        this.bi = bi;
    }

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

Solution

  • Well I would suggest using a MouseAdapter, and override mouseClicked(..). In mouseClicked check if pixel is alpha at point of click if it is do nothing, if not do something.

    • Always call super.paintComponent(..) as first call in overriden paintComponent method, but because, especially with buttons, this will redraw the JButton background call setContentAreaFilled(false) on JButton instance to stop this. You may also want setBorderPainted(false) too.

    Here is a small example I made (adapted from here):

    enter image description here

    if click on smiley:

    enter image description here

    import java.awt.Dimension;
    import java.awt.Graphics;
    import java.awt.Graphics2D;
    import java.awt.Image;
    import java.awt.RenderingHints;
    import java.awt.event.MouseAdapter;
    import java.awt.event.MouseEvent;
    import java.awt.image.BufferedImage;
    import java.net.URL;
    import javax.imageio.ImageIO;
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JOptionPane;
    import javax.swing.SwingUtilities;
    
    public class TransparentButton {
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
                @Override
                public void run() {
                    final JFrame frame = new JFrame();
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    
                    MyButton button = null;
    
                    try {
                        button = new MyButton(scaleImage(100, 100, ImageIO.read(new URL("http://2.bp.blogspot.com/-eRryNji1gQU/UCIPw0tY5bI/AAAAAAAASt0/qAvERbom5N4/s1600/original_smiley_face.png"))));
                    } catch (Exception ex) {
                        ex.printStackTrace();
                    }
    
                    button.addMouseListener(new MouseAdapter() {
                        @Override
                        public void mouseClicked(MouseEvent me) {
                            super.mouseClicked(me);
                            MyButton mb = ((MyButton) me.getSource());
                            if (!isAlpha(mb.getIconImage(), me.getX(), me.getY())) {
                                JOptionPane.showMessageDialog(frame, "You clicked the smiley");
                            }
                        }
    
                        private boolean isAlpha(BufferedImage bufImg, int posX, int posY) {
                            int alpha = (bufImg.getRGB(posX, posY) >> 24) & 0xFF;
                            return alpha == 0;
                        }
                    });
    
                    frame.add(button);
    
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        }
    
        public static BufferedImage scaleImage(int w, int h, Image img) throws Exception {
            BufferedImage bi;
            bi = new BufferedImage(w, h, BufferedImage.TRANSLUCENT);
            Graphics2D g2d = (Graphics2D) bi.createGraphics();
            g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON);
            g2d.addRenderingHints(new RenderingHints(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY));
            g2d.drawImage(img, 0, 0, w, h, null);
            return bi;
        }
    }
    
    class MyButton extends JButton {
    
        BufferedImage icon;
    
        MyButton(BufferedImage bi) {
            this.icon = ((BufferedImage) bi);
            setContentAreaFilled(false);
        }
    
        @Override
        public Dimension getPreferredSize() {
            return new Dimension(icon.getWidth(), icon.getHeight());
        }
    
        public BufferedImage getIconImage() {
            return icon;
        }
    
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.drawImage(icon, 0, 0, this);
        }
    }