Java 在带边框布局的JPanel上浮动JPanel

Java 在带边框布局的JPanel上浮动JPanel,java,swing,layout,Java,Swing,Layout,我有一个名为pnlMain的JPanel,布局设置为BorderLayout。面板内部有三个JPanel添加到PAGE\u START、中心和PAGE\u END。现在,我的要求是,如果单击设置按钮,它将在pnlMain上方显示一个透明的JPanel。这个透明的面板将包含一个不透明的、较小的、居中的面板,其中将包含设置内容 我知道我可以使用JLayeredPane来实现这一点,但查看it时发现,您只能使用绝对定位来放置不同深度的组件,我知道这是非常不鼓励的 是否有其他方法可以在不使用绝对定位的情

我有一个名为
pnlMain
JPanel
,布局设置为
BorderLayout
。面板内部有三个
JPanel
添加到
PAGE\u START
中心
PAGE\u END
。现在,我的要求是,如果单击设置按钮,它将在
pnlMain
上方显示一个透明的
JPanel
。这个透明的面板将包含一个不透明的、较小的、居中的面板,其中将包含设置内容

我知道我可以使用
JLayeredPane
来实现这一点,但查看it时发现,您只能使用绝对定位来放置不同深度的组件,我知道这是非常不鼓励的


是否有其他方法可以在不使用绝对定位的情况下执行此操作?

您可以使用父框架的玻璃窗格,这将允许您向其添加看起来覆盖在主要内容上的组件

基本上,我会创建一个
JPanel
,并将其设置为透明(
setOpaque(false)
)。我会将其布局管理器设置为类似于
GridBagLayout
(因为它将使用子组件的首选大小,并自动将其置于父容器的中心)

在此面板上,我将添加
设置
面板

最后,我将父框架的玻璃窗格设置为第一个(背衬)窗格,并使其可见

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

已更新

如果你不能自己使用顶层框架的玻璃窗格,那么你需要伪造它

此示例基本上使用了一个
JLayeredPane
,后面是一个
GridBagLayout

如果将
鼠标侦听器
键侦听器
添加到背景窗格,则可以使用到子组件的事件

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"));

        }
    }
}

另一种解决方案可能是通过拍摄当前面板的快照,并使用
CardLayout
,翻转到“设置”窗格,将快照用作“设置”窗格的背景图像(然后可以将效果应用于灰度缩放和模糊等)

FYI-您可以将布局管理器与
JLayeredPane
一起使用,但您需要一个布局管理器,它允许您将组件放置在彼此的顶部,如
GridBagLayout
,但可能有更简单的解决方案:d至少今天我帮助了一些人@MadProgrammer在
JPanel
层中是否有这样做的方法,因为我的
JPanel
可能嵌入在一个更大的帧中,这意味着如果我调用
getRootPane()
它将返回更大的帧,那么玻璃窗格将应用于更大的帧。不是吗?@onepotato,但据我所知,Java7使用@mKorbel时,
JLayer
是一个装饰器,它不允许与组件进行实时交互(东西刚刚画好)-可能是错误的,因为我只使用了
JXLayer
@尝试向UI添加其他组件并触发一些重绘,特别是那些应该发生在组件下面的。你可能不总是会遇到小故障,但当你遇到时,它将是非常棒的,这是关于这个问题的不止几个问题的来源