【问题标题】:Floating JPanel above a JPanel with BorderLayout在带有 BorderLayout 的 JPanel 上方浮动 JPanel
【发布时间】:2013-06-26 03:01:34
【问题描述】:

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

我知道我可以使用JLayeredPane 来做到这一点,但是查看tutorial 它说您只能使用绝对定位放置不同深度的组件,我知道这是非常不鼓励的。

有没有其他方法可以在不使用绝对定位的情况下做到这一点?

【问题讨论】:

  • 仅供参考-您可以使用带有 JLayeredPane 的布局管理器,但您需要一个允许您将组件放置在彼此之上的布局管理器,例如 GridBagLayout,但可能有更简单的解决方案

标签: java swing layout


【解决方案1】:

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

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

然后我将在此面板上添加Settings 面板。

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

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

看看How to use Root Panes

更新

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

这个例子基本上使用了JLayeredPane,由GridBagLayout支持

如果您将MouseListenerKeyListener 添加到背景窗格,您可以使用前往子组件的事件。

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 来伪造整个玻璃窗格,翻转到设置窗格,使用快照作为设置窗格的背景图像(可以然后可以将效果应用于灰度缩放和模糊)

【讨论】:

  • :D 至少我今天帮助了一些人
  • 先生。 @MadProgrammer 有没有办法在 JPanel 层中执行此操作,因为我的 JPanel 可能嵌入在更大的框架中,这意味着如果我调用 getRootPane() 它将返回更大的框架,然后玻璃窗格将应用于更大的框架。不是吗?
  • @onepotato agree,但Java7使用JLayer
  • @mKorbel 据我了解,JLayer 是一个装饰器,它不允许与组件进行实时交互(只是绘制的东西)-可能是错误的,因为我只使用了@ 987654340@
  • @OferYuval 尝试将其他组件添加到 UI 并触发一些重绘,尤其是那些应该在组件下方发生的重绘。您可能并不总是遇到故障,但是当您这样做时,它会非常棒,并且这是关于 SO 的多个问题的来源
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-12-06
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-02-12
相关资源
最近更新 更多