0

I would like the label "Test!" to sit behind the dark box, and to be able to see the background image behind. How can I achieve this?

This is a minimal example of my real problem, where I am trying to layer 2 frame-sized JPanels in order to create a navigation overlay over my application.

    private fun createAndShowGUI() {
        defaultCloseOperation = EXIT_ON_CLOSE

        contentPane = JLabel(ImageIcon("C:\\...\\bee.jpg"))
        layout = FlowLayout()

        //
        val translucentPanel: JPanel = object: JPanel() {
            override fun paintComponent(g: Graphics?) {
                super.paintComponent(g)

                val graphics = g!!.create() as Graphics2D
                graphics.composite = AlphaComposite.SrcOver.derive(0.5f)
                graphics.color = background
                graphics.fillRect(0, 0, width, height)
                graphics.dispose()
            }
        }
        translucentPanel.background = Color(0, 0, 0, 125)
        translucentPanel.preferredSize = Dimension(250, 150)
        translucentPanel.isOpaque = false

        //
        val backingPanel = JPanel()
        backingPanel.isOpaque = false
        backingPanel.layout = OverlayLayout(backingPanel)

        backingPanel.add(translucentPanel)
        backingPanel.add(Label("Test!"))

        //
        add(backingPanel)

        setSize(600, 400)
        isVisible = true
    }

Still can't see the label :(

Atom
  • 325
  • 1
  • 11
  • `panel.background = Color(0, 0, 0, 125)` isn't going to work, as Swing components are either opaque or transparent, not translucent, but you can "fake" it - [for example](https://stackoverflow.com/questions/32216625/how-to-make-a-translucent-jpanel-within-the-region-jpanel/32217554#32217554) – MadProgrammer Jul 15 '23 at 23:30
  • Hi @MadProgrammer, thanks for the reply. I've updated my code with the `paintComponent` method from your linked `TranslucentPane` code and set `isOpaque` to false, but I still can't see the Label :( – Atom Jul 16 '23 at 09:16

1 Answers1

1

Swing does not support alpha based background colors. Swing components are either fully opaque or fully transparent.

You can, however, fake it

enter image description here

import java.awt.AlphaComposite;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.Graphics2D;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JSlider;
import javax.swing.OverlayLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;

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

    public Main() {
        EventQueue.invokeLater(new Runnable() {
            @Override
            public void run() {
                JFrame frame = new JFrame();
                frame.add(new TestPane());
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class TestPane extends JPanel {
        public TestPane() {
            setLayout(new BorderLayout());
            setBackground(Color.RED);
            setBorder(new EmptyBorder(32, 32, 32, 32));

            JPanel overlayPane = new JPanel();
            overlayPane.setOpaque(false);
            overlayPane.setLayout(new OverlayLayout(overlayPane));

            TranslucentPane translucentPane = new TranslucentPane();
            translucentPane.setAlpha(0.5f);
            translucentPane.setBackground(Color.RED);

            overlayPane.add(translucentPane);
            overlayPane.add(new JLabel("This is a test"));

            add(overlayPane);

            JSlider slider = new JSlider(0, 100);
            slider.addChangeListener(new ChangeListener() {
                @Override
                public void stateChanged(ChangeEvent e) {
                    float alpha = slider.getValue() / 100f;
                    translucentPane.setAlpha(alpha);
                }
            });

            add(slider, BorderLayout.SOUTH);
        }
    }

    public class TranslucentPane extends JPanel {

        private float alpha = 1f;

        public TranslucentPane() {
            setOpaque(false);
        }

        public void setAlpha(float alpha) {
            this.alpha = alpha;
            repaint();
        }

        public float getAlpha() {
            return alpha;
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            Graphics2D g2d = (Graphics2D) g.create();
            g2d.setComposite(AlphaComposite.SrcOver.derive(getAlpha()));
            g2d.setColor(getBackground());
            g2d.fillRect(0, 0, getWidth(), getHeight());
            g2d.dispose();
        }

    }
}

Your first job is to get rid of translucentPanel.background = Color(0, 0, 0, 125), instead use Color.BLACK

Also, I had to change the order of the components, so the translucent pane was added first, then the label, this ensures that the translucent pane is rendered above the label

MadProgrammer
  • 343,457
  • 22
  • 230
  • 366
  • Hello again, @MadProgrammer, sorry that you had to post this again here, but I think I now understand you. This is perhaps not what I was searching for, but it will do for the moment, so thank you. – Atom Jul 16 '23 at 18:48