首先说一下JFrame组件的构成,JFrame有一个唯一的子容器JRootPane,
一下是api中关于JRootPane的注解
JRootpane
由一个 glassPane
和一个可选的 menuBar
以及一个 contentPane
组成。(JLayeredPane
负责管理 menuBar
和 contentPane
。)glassPane
位于所有窗格之上,以便能够截取鼠标移动。由于 glassPane
(与 contentPane
类似)可以是一个任意的组件,也可以设置 glassPane
来进行绘制。这样 glassPane
上的线条和图像可涵盖其下的窗体,不受其边界的限制。
尽管 menuBar
组件为可选,但 layeredPane
、contentPane
和 glassPane
总是存在的。试图将它们设置为 null
将生成异常。
要将组件添加到 JRootPane
(可选的菜单栏除外),您可以将对象添加到 JRootPane
的 contentPane
,如下所示:
rootPane.getContentPane().add(child);
可用同样的方法设置布局管理器、移除组件以及列出子级等。所有这些方法都是在 contentPane
上而不是 JRootPane
上调用的。
注:contentPane
的默认布局管理器是 BorderLayout
管理器。但是,JRootPane
使用一个自定义的 LayoutManager
。所以,如果您希望更改已添加到 JRootPane
中的组件的布局管理器,一定要确保使用如下代码:
rootPane.getContentPane().setLayout(new BoxLayout());
如果已在 JRootPane
上设置了 JMenuBar
组件,它将沿窗体的上边缘放置。contentPane
的位置和大小将进行调整以填充剩余的区域。(JMenuBar
和 contentPane
被添加到位于 JLayeredPane.FRAME_CONTENT_LAYER
层的 layeredPane
组件中。)
layeredPane
是 JRootPane
中所有子级的父级,既是菜单的直接父级,又是添加到 contentPane
中的所有组件的祖父级。它是 JLayeredPane
的实例,提供在若干层上添加组件的能力。在处理弹出菜单、对话框以及拖动时,即要求将组件置于窗格中所有其它组件之上的情况下,此功能非常有用。
glassPane
位于 JRootPane
中所有其它组件之上。这为在所有其它组件上绘图和截取鼠标事件提供了方便,这对拖动和绘图都非常有用。开发人员可在 glassPane
上使用 setVisible
控制 glassPane
在所有其它子级上面显示的时间。默认情况下,glassPane
为不可见。
JRootPane
所使用的自定义 LayoutManager
可确保:
glassPane
填充了 JRootPane
的整个可查看区域(边界 - insets)。
layeredPane
填充了 JRootPane
的整个可查看区域。(边界 - insets)
menuBar
位于 layeredPane
的上边缘。
contentPane
填充了整个可查看区域,减去 menuBar
(如果有)。
JRootPane
视图层次结构中的任何其它视图均忽略。
如果您替换 JRootPane
的 LayoutManager
,您将负责管理所有这些视图。所以通常情况下,应该确保更改的是 contentPane
的布局管理器,而不是 JRootPane
自身的布局管理器。
Swing 的绘制架构要求在所有其它组件之上的包含层次结构中有一个不透明的 JComponent
。这通常通过使用内容窗格来实现。如果要替换内容窗格,建议使用 setOpaque(true)
将内容窗格设置为不透明。另外,如果内容窗格重写 paintComponent
,还需要在 paintComponent
中用不透明颜色将背景完全填充。
JLayeredPane
为 JFC/Swing 容器添加了深度,允许组件在需要时互相重叠。Integer
对象指定容器中每个组件的深度,其中编号较高的组件位于其他组件之上。有关面向任务的文档和使用分层窗格的示例,请参阅《The Java Tutorial》中的 How to Use a Layered Pane 一节。
为方便起见,
JLayeredPane
将该深度范围分成几个不同的层。将组件放入相应的层,这样更容易确保组件正确地重叠,而不必担心为具体的深度指定编号:
- DEFAULT_LAYER
- 大多数组件位于的标准层。这是最底层。
- PALETTE_LAYER
- 调色板层位于默认层之上。它们对于浮动工具栏和调色板很有用,因此可以位于其他组件之上。
- MODAL_LAYER
- 该层用于模式对话框。它们将出现在容器中所有工具栏、调色板或标准组件的上面。
- POPUP_LAYER
- 弹出层显示在对话框的上面。这样,与组合框、工具提示和其他帮助文本关联的弹出式窗口将出现在组件、调色板或生成它们的对话框之上。
- DRAG_LAYER
- 拖动一个组件时,将该组件重分配到拖动层可确保将其定位在容器中的其他所有组件之上。完成拖动后,可将该组件重分配到其正常层。
可以使用 JLayeredPane
的方法 moveToFront(Component)
、moveToBack(Component)
和 setPosition
在组件所在层中对其进行重定位。还可以使用 setLayer
方法更改该组件的当前层。
详细信息
JLayeredPane
以类似 Container
的方式管理其子级列表,但允许在其内部定义多个层。对同一层中子级的管理就像普通的 Container
对象一样,但添加的功能是,当子组件重叠时,高层中的子组件显示在低层中的子组件之上。
每一层都是一个不同的整数。可以在调用 add 的过程中通过传递 Integer
对象,从而在 Component
上设置 layer 属性。
例如:
layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
或者
layeredPane.add(child, new Integer(10));
还可以通过在 JLayeredPane
上进行如下调用在 Component 上设置 layer 属性:
layeredPaneParent.setLayer(child, 10)
JLayeredPane
是该 Component 的父组件。应该将子组件添加到父组件之前 设置 layer 属性。
编号较高的层显示在编号较低的层之上。因此,对于每个组件,使用其层编号和字母即可,有代表性的列表顺序如下所示:
5a, 5b, 5c, 2a, 2b, 2c, 1a
其中最左边的组件最接近显示区的顶部。
可以通过调用 moveToFront
或 moveToBack
将组件移入到其所在层的顶部或底部位置。
还可以直接指定某层中组件的位置。有效的位置范围是从 0 到该层中组件数减一所得的值。值 -1 指示最底层位置。值 0 指示最顶层位置。与层的编号不同,较高的位置值显示在较低 处。
注: 此序列(通过 java.awt.Container 定义)与层的编号序列相反。可是通常使用的是 moveToFront
、moveToBack
和 setLayer
方法。
以下是使用方法 add(Component, layer, position) 的一些示例:调用 add(5x, 5, -1) 得到:
5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a
调用 add(5z, 5, 2) 得到:
5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a
调用 add(3a, 3, 7) 得到:
5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a
使用正常的 paint/event 机制会使 1a 出现在底部,5a 出现在所有其他组件之上。
注: 这些层只是一个逻辑构造,LayoutManager 将影响此容器的所有子组件,而不管其层设置如何。
下面是一个使用layeredpane的示例
/**
*
* @author: zhangtao
* msn: zht_dream@hotmail.com
* mail: zht_dream@hotmail.com
*/
public class InternalFrameTest extends JFrame {
public static void main(String[] args) {
InternalFrameTest test = new InternalFrameTest();
test.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
test.setSize(500, 400);
test.setLocationRelativeTo(null);
test.setVisible(true);
}
public InternalFrameTest() {
JPanel panel = new JPanel();
for (int i = 0; i < 10; i++) {
JButton button = new JButton(i + "");
panel.add(button);
}
this.setContentPane(panel);
JPanel controlPanel = createControlPanel(this.getContentPane());
JInternalFrame frame = new JInternalFrame();
frame.getContentPane().add(controlPanel);
frame.putClientProperty("JInternalFrame.isPalette", Boolean.valueOf(true));
frame.setTitle("control");
frame.pack();
frame.setLocation(30, 30);
frame.setVisible(true);
this.getLayeredPane().add(frame, 0);
}
public JPanel createControlPanel(final Container parent) {
JPanel panel = new JPanel(new GridLayout(3, 1, 2, 2));
final Color color = parent.getBackground();
JPanel panel1 = new JPanel(new FlowLayout());
panel1.add(new JLabel("r"));
final JSlider sliderRed = new JSlider(0, 255);
sliderRed.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
parent.setBackground(new Color(sliderRed.getValue(), color.getGreen(), color.getBlue()));
}
});
sliderRed.setValue(color.getRed());
panel1.add(sliderRed);
JPanel panel2 = new JPanel(new FlowLayout());
panel2.add(new JLabel("g"));
final JSlider sliderGreen = new JSlider(0, 255);
sliderGreen.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
parent.setBackground(new Color(color.getRed(), sliderGreen.getValue(), color.getBlue()));
}
});
sliderGreen.setValue(color.getGreen());
panel2.add(sliderGreen);
JPanel panel3 = new JPanel(new FlowLayout());
panel3.add(new JLabel("b"));
final JSlider sliderBlue = new JSlider(0, 255);
sliderBlue.addChangeListener(new ChangeListener() {
public void stateChanged(ChangeEvent e) {
parent.setBackground(new Color(color.getRed(), color.getGreen(), sliderBlue.getValue()));
}
});
sliderBlue.setValue(color.getBlue());
panel3.add(sliderBlue);
panel.add(panel1);
panel.add(panel2);
panel.add(panel3);
return panel;
}
}