将 JButton 叠加到内容窗格中带有 JTabbedPan 的 JFrame 上?

Overlaying a JButton onto a JFrame with a JTabbedPan in its content pane?

下面的代码创建了一个框架,在框架的 contentPane 中有一个 JTabbedPane,并在框架的分层窗格中直接添加了一个 "Help" 按钮 - 索引高于默认值,因此它应该始终绘制在前面选项卡式窗格。但是如您所见,如果您 运行 它,只要您单击其中一个选项卡(或者,在 Mac 上,只要您将鼠标悬停在选项卡上),"Help"按钮被涂满 - 即消失。您必须调整框架大小才能使 "Help" 按钮重新出现。

这是 Java 错误还是我做错了什么?如果是后者,需要做些什么来解决这个问题?我咨询过 https://docs.oracle.com/javase/tutorial/uiswing/components/rootpane.html and https://docs.oracle.com/javase/tutorial/uiswing/components/toplevel.html .

请原谅 "Help" 按钮位置不佳。我只是想写一个快速测试来包含在这里。这个想法是在 JTabbedPane 未使用的 space 中覆盖一个 "Help" 图标按钮。

import java.awt.BorderLayout;
import java.awt.Dimension;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLayeredPane;
import javax.swing.JPanel;
import javax.swing.JTabbedPane;
import javax.swing.SwingUtilities;
public class TabTest {
    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            public void run() {
                JFrame frame = new JFrame();
                JTabbedPane tp = new JTabbedPane();
                tp.addTab("hello", new JPanel());
                tp.addTab("there", new JPanel());
                frame.getContentPane().add(tp, BorderLayout.CENTER);
                JLayeredPane layeredPane = frame.getRootPane().getLayeredPane();
                JButton helpButton = new JButton("Help");
                helpButton.setBounds(800, 5, 50, 20);
                layeredPane.add(helpButton, 400);
                frame.setSize(new Dimension(900, 800));
                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                frame.setVisible(true);
            }
        });
    }
}

这是 JLayeredPane 的常见误解。

如果您查看 Container 的 JavaDocs,您会注意到(至少)有两个 add 方法

您需要回答的问题是,您实际呼叫的是哪一个?

两个 JavaDocs for JLayeredPane and How to use JLayeredPane 都表明您应该调用第二个。

虽然第一个会影响组件的z-ordering,但不能保证组件位置不会改变。

而不是:

layeredPane.add(helpButton, 400);

你应该使用:

layeredPane.add(helpButton, new Integer(400));

这会将值作为约束传递给容器,而不是容器层次结构中的所需位置 - 是的,我知道合适

另一种解决方案可能是使用 glassPane,例如...

JFrame frame = new JFrame();
JTabbedPane tp = new JTabbedPane();
tp.addTab("hello", new JPanel());
tp.addTab("there", new JPanel());
frame.getContentPane().add(tp, BorderLayout.CENTER);

// Null layout used here for demonstration purposes only
JPanel glassPane = new JPanel(null);
glassPane.setOpaque(false);
frame.getRootPane().setGlassPane(glassPane);
// This is important, as setGlassPane makes it invisible
glassPane.setVisible(true);

JButton helpButton = new JButton("Help");
helpButton.setBounds(800, 5, 50, 20);
glassPane.add(helpButton);

frame.setSize(new Dimension(900, 800));
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
frame.setVisible(true);