Search code examples
javaswingjpaneltransparencyjwindow

JPanel on JWindow is not transparent if `set setOpaque(false);` - why?


How to make JPanel to be transparent in this example? The gradient background is not visible:

package test;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.GradientPaint;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.BoxLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JWindow;

public class PaintJPanelOnJWindow extends JWindow {

    public PaintJPanelOnJWindow() {

        JPanel panel = new JPanel();

        panel.setPreferredSize(new Dimension(350, 120));
        panel.setMinimumSize(new Dimension(350, 120));
        panel.setMaximumSize(new Dimension(350, 120));

        panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));
        panel.setOpaque(false);

        JLabel someText = new JLabel("I'm not transparent and my JPanel too :(");
        someText.setOpaque(false);
        panel.add(someText);
        add(panel);

        pack();
        setLocationRelativeTo(null);
        setVisible(true);
    }

    @Override
    public void paint(Graphics g) {

        Graphics2D g2d = (Graphics2D) g.create();
        try {
            int w = getWidth(), h = getHeight();
            g2d.setPaint(new GradientPaint(0, 0, Color.RED, 0, h, Color.WHITE));
            g2d.fillRect(0, 0, w, h);
        } finally {
            g2d.dispose();
        }
        super.paint(g);
    }
}

Solution

  • The immediate problem is that

    super.paint(g);
    

    is being called after the custom painting code in the paint method which will cause any previous painting to be lost. Calling panel.setOpaque(false) has no effect what is done in the paint method. Calling setOpaque for any of the components in the question is unnecessary - by default the backgrounds are displayed when custom painting is correctly implemented.

    This should be done by overriding the paintComponent method. This means creating a new JPanel and placing the custom painting functionality there rather than in a top level container such as a JWindow.

    Example:

    enter image description here

    public class PaintJPanelApp {
    
    
        public static void main(String[] args) {
            SwingUtilities.invokeLater(new Runnable() {
    
                @Override
                public void run() {
                    JFrame frame = new JFrame("Gradient App");
                    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                    frame.setUndecorated(true);
                    frame.setLocationRelativeTo(null);
    
                    JLabel someText = new JLabel("I AM transparent and my JPanel too :)");
                    GradientPanel gradientPanel = new GradientPanel();
                    gradientPanel.add(someText);
                    frame.add(gradientPanel);
    
                    frame.pack();
                    frame.setVisible(true);
                }
            });
        }
    
        static class GradientPanel extends JPanel {
    
    
            @Override
            protected void paintComponent(Graphics g) {
                super.paintComponent(g);
                int w = getWidth(); 
                int h = getHeight();
                Graphics2D g2d = (Graphics2D) g;
                g2d.setPaint(new GradientPaint(0, 0, Color.RED, 0, h, Color.WHITE));
                g2d.fillRect(0, 0, w, h);
            }
        }
    }