Dan
Dan

Reputation: 7724

Missing JPanel in JLayeredPane

I was working on an overlay for a JPanel but I have a slight problem, the transparency of the overlay sees straight through to the JFrame.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GUI extends JFrame {
    private GUI() {
        super("Recorder Part");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());
        JLayeredPane layers = new Overlay();
        add(layers);

        pack();

        getContentPane().setBackground(Color.GREEN);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new GUI());
    }

    private class Overlay extends JLayeredPane {
        JPanel base;
        JPanel overlay;

        private Overlay() {
            setPreferredSize(new Dimension(800, 100));

            createBase();
            createOverlay();

            add(base, new Integer(0));
            add(overlay, new Integer(1));
        }


        private void createBase() {
            base = new JPanel();
            base.setPreferredSize(new Dimension(800, 100));
            base.setBounds(0, 0, 800, 100);
            base.setBackground(Color.BLUE);
            base.setOpaque(true);

            base.add(new JLabel("Hello"));
        }

        private void createOverlay() {
            overlay = new JPanel();
            overlay.setPreferredSize(new Dimension(800, 100));
            overlay.setBounds(0, 0, 800, 100);
            overlay.setBackground(new Color(255, 0, 0, 0));
        }
    }
}

How can I fix this so that when the JPanel called overlay is transparent, the Jpanel called base can be seen and not the JFrame?


Edit

I found that this problem only occurs when the overlay panel has one dimension that is greater than or equal to the dimensions of the base panel. This can be seen by adjusting the size of the frame in this example.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;

@SuppressWarnings("serial")
public class GUI extends JFrame {
    private GUI() {
        super("Recorder Part");
        setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        setLayout(new BorderLayout());
        JLayeredPane layers = new Overlay();
        add(layers);

        pack();

        getContentPane().setBackground(Color.GREEN);
        setVisible(true);
    }

    public static void main(String[] args) {
        EventQueue.invokeLater(() -> new GUI());
    }

    private class Overlay extends JLayeredPane {
        JPanel base;
        JPanel overlay;

        private Overlay() {
            addComponentListener(new Resize());
            setPreferredSize(new Dimension(800, 100));

            createBase();
            createOverlay();

            add(base, new Integer(0));
            add(overlay, new Integer(1));
        }


        private void createBase() {
            base = new JPanel();
            base.setLocation(0, 0);
            base.setBackground(Color.BLUE);
            base.setOpaque(true);

            base.add(new JLabel("Hello"));
        }

        private void createOverlay() {
            overlay = new JPanel();
            overlay.setLocation(0, 0);
            overlay.setSize(new Dimension(800, 100));
            overlay.setBackground(new Color(255, 0, 0, 128));
        }

        private class Resize extends ComponentAdapter {
            @Override
            public void componentResized(ComponentEvent e) {
                System.out.println("Resized");
                base.setSize(new Dimension(getParent().getWidth(), getParent().getHeight()));
            }
        }
    }
}

This is undesirable as the overlay panel needs to be the exact same size of the base panel. I would appreciate any help.

Upvotes: 1

Views: 266

Answers (1)

user85421
user85421

Reputation: 29670

I have the felling that this is a bug. Change the bounds so it doesn't fully overlap the base to o see what happens:

overlay.setBounds(0, 0, 799, 100); // or (1, 0, 800, 100)

probably some kind of optimization, like ignoring a component if it is being completely obscured by another component, but without considering transparency in that optimization [:-|

EDIT:

that is definitively the problem - paintChildren of JComponent does some kind of optimization based on children being totally obscured by other children.

I found two solutions, the first one is probably the correct one- set the overlay to non-opaque:

overlay.setOpaque(false);

this has the drawback that the background color is not being used at all.

Second is more a workarround - make the JLayeredPane return true for optimizedDrawingEnabled, this will stop the JComponent from doing it:

private class Overlay extends JLayeredPane {

    /// ...

    @Override
    public boolean isOptimizedDrawingEnabled() {
        return true;
    }
}

but not sure what may stop working by doing that, so I would prefer the first solution!

Upvotes: 1

Related Questions