How to Draw a Transparent Background?
Asked Answered
G

1

1

I am trying to make a piece of a JPanel transparent, but I cannot quite get it to work. Is it possible to do this?

import java.awt.*;
import javax.swing.*;

public class ClearPanel extends JPanel{
public static void main(String[] args) {
    ClearPanel c = new ClearPanel();
    c.setPreferredSize(new Dimension(200, 200));
    c.setOpaque(false);

    JPanel backPanel = new JPanel();
    backPanel.setBackground(Color.CYAN);

    backPanel.add(c);

    JFrame f = new JFrame();
    f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    f.setContentPane(backPanel);
    f.pack();
    f.setLocationRelativeTo(null);
    f.setVisible(true);
}

@Override
protected void paintComponent(Graphics g) {
    super.paintComponent(g);
    g.fillOval(0, 0, 200, 200);
    g.clearRect(45, 45, 50, 50);

    Graphics2D g2 = (Graphics2D) g;
    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.0f));
    g2.fillRect(75, 75, 50, 50);
}
}

The oval should be opaque, but the rectangles I would like to be transparent. By transparent, I mean that I should be able to see the panel behind the ClearPanel.

Going off of MadProgrammer's answer, is there any way to make that gray box draw where it is outside of the area, but remain transparent where it is in the area?

    @Override
    protected void paintComponent(Graphics g) {
        super.paintComponent(g);
        Rectangle fill = new Rectangle(getWidth(), getHeight());
        Graphics2D g2d = (Graphics2D) g.create();

        Rectangle hole = new Rectangle(0, 0, 100, 100);

        Area area = new Area(fill);
        area.subtract(new Area(hole));
        g2d.setColor(getBackground());
        g2d.fill(area);

        g2d.setColor(Color.RED);
        g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
        g2d.fill(hole);

        g2d.setComposite(AlphaComposite.SrcOver.derive(1.0f));
        g2d.setColor(Color.DARK_GRAY);
        if(area.contains(0,0,100,200))
            g2d.fillRect(0, 0, 100, 200);

        g2d.dispose();      
    }
Glantz answered 9/3, 2013 at 10:20 Comment(3)
doesn't drawRect() fulfill your requirement?Heraclea
@Heraclea no because I would not be able to see through the Jpanel, I would still see the oval where the rect is drawn.Glantz
"I am trying to make a piece of a JPanel transparent.." Why, what application feature does it provide? I ask because there are probably better ways to achieve that feature.Wilek
F
6

The problem you have is, by default, JPanel is opaque, meaning that the repaint will NOT paint anything under it.

You need to set the the panel to transparent and then take over the painting of the background.

Now, the real trick begins. If you simply fill the component and then try and paint transparent section over the top of it, you will simply be painting a transparent section over a opaque background...not very helpful.

What you need to do is not fill the area you want to remain transparent.

You can accomplish this by using a Area shape, which has a neat trick of been able to append/add and remove shapes from it.

enter image description here

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.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TransparentPane {

    public static void main(String[] args) {
        new TransparentPane();
    }

    public TransparentPane() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                BackgroundPane backgroundPane = new BackgroundPane();
                backgroundPane.setBackground(Color.RED);
                backgroundPane.setLayout(new BorderLayout());
                backgroundPane.add(new TranslucentPane());

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(backgroundPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BackgroundPane extends JPanel {

        private BufferedImage bg;

        public BackgroundPane() {
            try {
                bg = ImageIO.read(new File("/path/to/your/image.jpg"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bg != null) {
                int width = getWidth() - 1;
                int height = getHeight() - 1;
                int x = (width - bg.getWidth()) / 2;
                int y = (height - bg.getHeight()) / 2;
                g.drawImage(bg, x, y, this);
            }
        }

    }

    public class TranslucentPane extends JPanel {

        public TranslucentPane() {
            setOpaque(false);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Rectangle fill = new Rectangle(getWidth(), getHeight());
            Graphics2D g2d = (Graphics2D) g.create();

            int width = getWidth() - 1;
            int height = getHeight() - 1;
            int radius = Math.min(width, height) / 2;
            int x = (width - radius) / 2;
            int y = (height - radius) / 2;

            Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);

            Area area = new Area(fill);
            area.subtract(new Area(hole));
            g2d.setColor(getBackground());
            g2d.fill(area);

            g2d.setColor(Color.RED);
            g2d.setComposite(AlphaComposite.SrcOver.derive(0.25f));
            g2d.fill(hole);

            g2d.dispose();
        }

    }

}

Update

Well, that took a little longer the I expected...

enter image description here

Basically, we need to create a mask of the shape that subtracts the hole from the rectangle we want to display, then subtract that result from the rectangle we want to diplay

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.Rectangle;
import java.awt.geom.Area;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.imageio.ImageIO;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;

public class TransparentPane {

    public static void main(String[] args) {
        new TransparentPane();
    }

    public TransparentPane() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                try {
                    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
                } catch (ClassNotFoundException ex) {
                } catch (InstantiationException ex) {
                } catch (IllegalAccessException ex) {
                } catch (UnsupportedLookAndFeelException ex) {
                }

                BackgroundPane backgroundPane = new BackgroundPane();
                backgroundPane.setBackground(Color.RED);
                backgroundPane.setLayout(new BorderLayout());
                backgroundPane.add(new TranslucentPane());

                JFrame frame = new JFrame("Test");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(backgroundPane);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class BackgroundPane extends JPanel {

        private BufferedImage bg;

        public BackgroundPane() {
            try {
                bg = ImageIO.read(new File("/Users/swhitehead/Dropbox/MegaTokyo/Evil_Small.jpg"));
            } catch (IOException ex) {
                ex.printStackTrace();
            }
        }

        @Override
        public Dimension getPreferredSize() {
            return bg == null ? super.getPreferredSize() : new Dimension(bg.getWidth(), bg.getHeight());
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            if (bg != null) {
                int width = getWidth() - 1;
                int height = getHeight() - 1;
                int x = (width - bg.getWidth()) / 2;
                int y = (height - bg.getHeight()) / 2;
                g.drawImage(bg, x, y, this);
            }
        }

    }

    public class TranslucentPane extends JPanel {

        public TranslucentPane() {
            setOpaque(false);
        }

        @Override
        public Dimension getPreferredSize() {
            return new Dimension(200, 200);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Rectangle fill = new Rectangle(getWidth(), getHeight());
            Graphics2D g2d = (Graphics2D) g.create();

            int width = getWidth() - 1;
            int height = getHeight() - 1;
            int radius = Math.min(width, height) / 2;
            int x = (width - radius) / 2;
            int y = (height - radius) / 2;

            Ellipse2D hole = new Ellipse2D.Float(x, y, radius, radius);

            Area area = new Area(fill);
            area.subtract(new Area(hole));
            g2d.setColor(getBackground());
            g2d.fill(area);

            g2d.setColor(Color.RED);
            g2d.setComposite(AlphaComposite.SrcOver.derive(0.0f));
            g2d.fill(hole);
            g2d.dispose();

            g2d = (Graphics2D) g.create();

            // Basically, we create an area that is subtraction of the window/rectangle
            // from the whole.  This leaves us with a rectangle (with a hole in it)
            // that doesn't include the area where the whole is...
            Rectangle win = new Rectangle(
                            x + (radius / 2), 
                            y + (radius / 2), radius, (radius / 4));
            area = new Area(win);
            area.subtract(new Area(hole));

            // Then we create a area that is a subtraction of the original rectangle
            // from the one with a "hole" in it...
            Area actual = new Area(win);
            actual.subtract(area);
            g2d.setColor(Color.BLUE);
            g2d.setComposite(AlphaComposite.SrcOver.derive(0.5f));
            g2d.fill(actual);

            g2d.dispose();
        }        
    }
}
Flitch answered 9/3, 2013 at 10:50 Comment(2)
Thanks for the answer, I've updated my question if you want to take a look at that too. Thanks again.Glantz
Change the AlphaComposite type. You could also start with Area of the rectangle (that overlaps), subtract the transparent part from, fill this as opaque, then, starting with the same area, subtract the area outside of the transparent area and fill that...Flitch

© 2022 - 2024 — McMap. All rights reserved.