Search code examples
javaswinggraphics2dbufferstrategy

How to draw images on transparent window?


I'm trying to draw Images with Graphics2D on JFrame.
But this code only displays blank background.
How to do that?

Java Version: SE-1.6
IDE: Eclipse

My code looks like this:

import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.image.BufferStrategy;
import java.awt.geom.Line2D;
import java.util.TimerTask;

import javax.swing.JFrame;

public class GraphicTest extends JFrame{

    public static void main(String[] args) {
        GraphicTest gt = new GraphicTest();
        gt.start();
    }

    JFrame frame;
    BufferStrategy strategy;

    GraphicTest(){
        int width = 320;
        int height = 240;

        this.frame = new JFrame("test");

        this.frame.setSize(width, height);
        this.frame.setLocationRelativeTo(null);
        this.frame.setLocation(576, 336);
        this.frame.setDefaultCloseOperation(javax.swing.JFrame.EXIT_ON_CLOSE);

        this.frame.setUndecorated(true);
        this.frame.setBackground(new Color(0, 0, 0, 50));

        this.frame.setVisible(true);

        this.frame.setIgnoreRepaint(true);
        this.frame.createBufferStrategy(2);
        this.strategy = this.frame.getBufferStrategy();
    }

    public void onExit(){
        System.exit(0);
    }

    void start(){
        java.util.Timer timer = new java.util.Timer();
        timer.schedule(new RenderTask(), 0, 16);
    }

    class RenderTask extends TimerTask{
        int count = 0;

        @Override
        public void run() {
            GraphicTest.this.render();
        }
    }

    void render() {
        // Some moving images
        Graphics2D g2 = (Graphics2D)this.strategy.getDrawGraphics();
        g2.setStroke(new BasicStroke(5.0f));
        Line2D line = new Line2D.Double(20, 40, 120, 140);
        g2.draw(line);
        this.strategy.show();
    }
}

Thank you for any help you can provide.


Solution

    • BufferStrategy is normally associated with heavy weight components, which don't have any concept of transparency.
    • Transparent and translucent (per alpha pixeling) is not "officially" supported under Java 6
    • Making a window translucent effects anything else painted to it...this very annoying, regardless if you are using Java 6 or 7

    The secret is to make the Window transparent to begin with, then overlay a transparent component that has a special "translucent" paint effect.

    Under Java 6 (update 10 I think), there became available a private API called AWTUtilities which provide the ability to make a window transparent or translucent, the following example is based on that API.

    Bouncy Birdy

    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.Window;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    import java.awt.image.BufferedImage;
    import java.io.File;
    import java.io.IOException;
    import java.lang.reflect.Method;
    import javax.imageio.ImageIO;
    import javax.swing.JFrame;
    import javax.swing.JPanel;
    import javax.swing.Timer;
    import javax.swing.UIManager;
    import javax.swing.UnsupportedLookAndFeelException;
    
    public class TransparentWindowAnimation {
    
        public static void main(String[] args) {
            new TransparentWindowAnimation();
        }
    
        public TransparentWindowAnimation() {
            EventQueue.invokeLater(new Runnable() {
                @Override
                public void run() {
                    try {
                        UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                    } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) {
                    }
    
                    if (supportsPerAlphaPixel()) {
                        try {
                            JFrame frame = new JFrame("Testing");
                            frame.setUndecorated(true);
                            setOpaque(frame, false);
                            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                            frame.setLayout(new BorderLayout());
                            frame.add(new PaintPane());
                            frame.pack();
                            frame.setLocationRelativeTo(null);
                            frame.setVisible(true);
                        } catch (Exception exp) {
                            exp.printStackTrace();
                        }
                    } else {
                        System.err.println("Per pixel alphering is not supported");
                    }
                }
            });
        }
    
        public static boolean supportsPerAlphaPixel() {
            boolean support = false;
            try {
                Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
                support = true;
            } catch (Exception exp) {
            }
            return support;
        }
    
        public static void setOpaque(Window window, boolean opaque) throws Exception {
            try {
                Class<?> awtUtilsClass = Class.forName("com.sun.awt.AWTUtilities");
                if (awtUtilsClass != null) {
                    Method method = awtUtilsClass.getMethod("setWindowOpaque", Window.class, boolean.class);
                    method.invoke(null, window, opaque);
                }
            } catch (Exception exp) {
                throw new Exception("Window opacity not supported");
            }
        }
    
        public class PaintPane extends JPanel {
    
            private BufferedImage img;
    
            private int xPos, yPos = 100;
            private int xDelta = 0;
            private int yDelta = 0;
    
            public PaintPane() {
                while (xDelta == 0) {
                    xDelta = (int)((Math.random() * 8)) - 4;
                }
                while (yDelta == 0) {
                    yDelta = (int)((Math.random() * 8)) - 4;
                }
                setOpaque(false);
                try {
                    img = ImageIO.read(new File("AngryBird.png"));
                } catch (IOException ex) {
                    ex.printStackTrace();
                }
    
                Timer timer = new Timer(40, new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        xPos += xDelta;
                        yPos += yDelta;
                        if (xPos - (img.getWidth() / 2) <= 0) {
                            xPos = img.getWidth() / 2;
                            xDelta *= -1;
                        }
                        if (xPos + (img.getWidth() / 2) >= getWidth()) {
                            xPos = getWidth() - (img.getWidth() / 2);
                            xDelta *= -1;
                        }
                        if (yPos - (img.getHeight() / 2) <= 0) {
                            yPos = img.getHeight() / 2;
                            yDelta *= -1;
                        }
                        if (yPos + (img.getHeight() / 2) >= getHeight()) {
                            yPos = getHeight() - (img.getHeight() / 2);
                            yDelta *= -1;
                        }
                        repaint();
                    }
                });
                timer.start();
            }
    
            @Override
            public Dimension getPreferredSize() {
                return new Dimension(200, 200);
            }
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                Graphics2D g2d = (Graphics2D) g.create();
                g2d.setColor(new Color(128, 128, 128, 128));
                g2d.fillRect(0, 0, getWidth(), getHeight());
                int x = xPos - (img.getWidth() / 2);
                int y = yPos - (img.getHeight()/ 2);
                g2d.drawImage(img, x, y, this);
                g2d.dispose();
            }
        }
    
    }