Bnrdo
Bnrdo

Reputation: 5474

Floating JPanel above a JPanel with BorderLayout

I have a JPanel called pnlMain with a layout set to BorderLayout. Inside the panel are three JPanel added to PAGE_START, CENTER, and PAGE_END. Now, my requirement is if the Settings button is clicked, it will display a transparent JPanel above pnlMain. This transparent panel will then contain an opaque, smaller, centered panel, that will contain the settings stuff.

I know I can do this using JLayeredPane, but looking at the tutorial it says that you can only put components of different depth using absolute positioning which I'm aware is highly discouraged.

Is there some other way to do this without using absolute positioning?

Upvotes: 3

Views: 7116

Answers (1)

MadProgrammer
MadProgrammer

Reputation: 347334

You can use the glass pane of the parent frame, which will allow you to add components to it that will appear to overlaid over the main content.

Basically, I would, create a JPanel and set it to be transparent (setOpaque(false)). I would set it's layout manager to something like GridBagLayout (as it will use the preferred size of the child component and center it automatically within it's parent container).

Onto this panel I would then add the Settings panel.

Finally, I would set the parent frame's glass pane to the first (backing) pane and make it visible.

frame.getRootPane().setGlassPane(backingPane); // Or similar

Take a look at How to use Root Panes

Updated

If you can't use the glass pane of the top level frame yourself, then you need to fake it.

This example basically uses a JLayeredPane backed by a GridBagLayout

enter image description here

If you add a MouseListener and KeyListener to the background pane you can consume events going to the child components.

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.EventQueue;
import java.awt.Graphics;
import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.border.EmptyBorder;

public class FloatingPane {

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

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

                final WorkPane workPane = new WorkPane();
                JButton settings = new JButton("Settings");
                settings.addActionListener(new ActionListener() {
                    @Override
                    public void actionPerformed(ActionEvent e) {
                        workPane.toggleSettings();
                    }
                });

                JFrame frame = new JFrame("Testing");
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setLayout(new BorderLayout());
                frame.add(workPane);
                frame.add(settings, BorderLayout.SOUTH);
                frame.pack();
                frame.setLocationRelativeTo(null);
                frame.setVisible(true);
            }
        });
    }

    public class WorkPane extends JLayeredPane {
        private final BackingPane backingPane;

        public WorkPane() {

            setLayout(new GridBagLayout());

            GridBagConstraints gbc = new GridBagConstraints();
            gbc.gridx = 1;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.fill = GridBagConstraints.BOTH;
            add(createLabel("Center", Color.BLUE), gbc);

            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 0;
            gbc.weighty = 0;
            gbc.fill = GridBagConstraints.VERTICAL;
            add(createLabel("Left", Color.RED), gbc);
            gbc.gridx = 2;
            add(createLabel("Right", Color.GREEN), gbc);

            gbc.gridx = 0;
            gbc.gridy = 0;
            gbc.weightx = 1;
            gbc.weighty = 1;
            gbc.gridheight = GridBagConstraints.REMAINDER;
            gbc.gridwidth = GridBagConstraints.REMAINDER;
            gbc.fill = GridBagConstraints.BOTH;

            backingPane = new BackingPane();
            backingPane.add(new SettingsPane());
            backingPane.setVisible(false);
            add(backingPane, gbc);

            setLayer(backingPane, DEFAULT_LAYER + 1);

        }

        public void toggleSettings() {

            backingPane.setVisible(!backingPane.isVisible());

        }

        protected JLabel createLabel(String text, Color bg) {

            JLabel label = new JLabel(text);
            label.setHorizontalAlignment(JLabel.CENTER);
            label.setOpaque(true);
            label.setBackground(bg);

            return label;

        }
    }

    public class BackingPane extends JPanel {

        public BackingPane() {
            setLayout(new GridBagLayout());
            setOpaque(false);
        }

        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            g.setColor(new Color(128, 128, 128, 192));
            g.fillRect(0, 0, getWidth(), getHeight());
        }

    }

    public class SettingsPane extends JPanel {

        public SettingsPane() {

            setBorder(new EmptyBorder(10, 10, 10, 10));
            add(new JLabel("Settings"));

        }
    }
}

Another solution might be to fake the entire glass pane by taking a snap shot of the current panel and using a CardLayout, flip to the settings pane, using the snap shot as the backgound image for the settings pane (which can could then apply effects to like gray scaling and bluring)

Upvotes: 7

Related Questions