首先說(shuō)一下JFrame組件的構(gòu)成,JFrame有一個(gè)唯一的子容器JRootPane,
一下是api中關(guān)于JRootPane的注解
JRootpane
由一個(gè) glassPane
和一個(gè)可選的 menuBar
以及一個(gè) contentPane
組成。(JLayeredPane
負(fù)責(zé)管理 menuBar
和 contentPane
。)glassPane
位于所有窗格之上,以便能夠截取鼠標(biāo)移動(dòng)。由于 glassPane
(與 contentPane
類(lèi)似)可以是一個(gè)任意的組件,也可以設(shè)置 glassPane
來(lái)進(jìn)行繪制。這樣 glassPane
上的線條和圖像可涵蓋其下的窗體,不受其邊界的限制。
盡管 menuBar
組件為可選,但 layeredPane
、contentPane
和 glassPane
總是存在的。試圖將它們?cè)O(shè)置為 null
將生成異常。
要將組件添加到 JRootPane
(可選的菜單欄除外),您可以將對(duì)象添加到 JRootPane
的 contentPane
,如下所示:
rootPane.getContentPane().add(child);
可用同樣的方法設(shè)置布局管理器、移除組件以及列出子級(jí)等。所有這些方法都是在 contentPane
上而不是 JRootPane
上調(diào)用的。
注:contentPane
的默認(rèn)布局管理器是 BorderLayout
管理器。但是,JRootPane
使用一個(gè)自定義的 LayoutManager
。所以,如果您希望更改已添加到 JRootPane
中的組件的布局管理器,一定要確保使用如下代碼:
rootPane.getContentPane().setLayout(new BoxLayout());
如果已在 JRootPane
上設(shè)置了 JMenuBar
組件,它將沿窗體的上邊緣放置。contentPane
的位置和大小將進(jìn)行調(diào)整以填充剩余的區(qū)域。(JMenuBar
和 contentPane
被添加到位于 JLayeredPane.FRAME_CONTENT_LAYER
層的 layeredPane
組件中。)
layeredPane
是 JRootPane
中所有子級(jí)的父級(jí),既是菜單的直接父級(jí),又是添加到 contentPane
中的所有組件的祖父級(jí)。它是 JLayeredPane
的實(shí)例,提供在若干層上添加組件的能力。在處理彈出菜單、對(duì)話框以及拖動(dòng)時(shí),即要求將組件置于窗格中所有其它組件之上的情況下,此功能非常有用。
glassPane
位于 JRootPane
中所有其它組件之上。這為在所有其它組件上繪圖和截取鼠標(biāo)事件提供了方便,這對(duì)拖動(dòng)和繪圖都非常有用。開(kāi)發(fā)人員可在 glassPane
上使用 setVisible
控制 glassPane
在所有其它子級(jí)上面顯示的時(shí)間。默認(rèn)情況下,glassPane
為不可見(jiàn)。
JRootPane
所使用的自定義 LayoutManager
可確保:
glassPane
填充了 JRootPane
的整個(gè)可查看區(qū)域(邊界 - insets)。
layeredPane
填充了 JRootPane
的整個(gè)可查看區(qū)域。(邊界 - insets)
menuBar
位于 layeredPane
的上邊緣。
contentPane
填充了整個(gè)可查看區(qū)域,減去 menuBar
(如果有)。
JRootPane
視圖層次結(jié)構(gòu)中的任何其它視圖均忽略。
如果您替換 JRootPane
的 LayoutManager
,您將負(fù)責(zé)管理所有這些視圖。所以通常情況下,應(yīng)該確保更改的是 contentPane
的布局管理器,而不是 JRootPane
自身的布局管理器。
Swing 的繪制架構(gòu)要求在所有其它組件之上的包含層次結(jié)構(gòu)中有一個(gè)不透明的 JComponent
。這通常通過(guò)使用內(nèi)容窗格來(lái)實(shí)現(xiàn)。如果要替換內(nèi)容窗格,建議使用 setOpaque(true)
將內(nèi)容窗格設(shè)置為不透明。另外,如果內(nèi)容窗格重寫(xiě) paintComponent
,還需要在 paintComponent
中用不透明顏色將背景完全填充。

JLayeredPane
為 JFC/Swing 容器添加了深度,允許組件在需要時(shí)互相重疊。Integer
對(duì)象指定容器中每個(gè)組件的深度,其中編號(hào)較高的組件位于其他組件之上。有關(guān)面向任務(wù)的文檔和使用分層窗格的示例,請(qǐng)參閱《The Java Tutorial》中的 How to Use a Layered Pane 一節(jié)。
為方便起見(jiàn),
JLayeredPane
將該深度范圍分成幾個(gè)不同的層。將組件放入相應(yīng)的層,這樣更容易確保組件正確地重疊,而不必?fù)?dān)心為具體的深度指定編號(hào):
- DEFAULT_LAYER
- 大多數(shù)組件位于的標(biāo)準(zhǔn)層。這是最底層。
- PALETTE_LAYER
- 調(diào)色板層位于默認(rèn)層之上。它們對(duì)于浮動(dòng)工具欄和調(diào)色板很有用,因此可以位于其他組件之上。
- MODAL_LAYER
- 該層用于模式對(duì)話框。它們將出現(xiàn)在容器中所有工具欄、調(diào)色板或標(biāo)準(zhǔn)組件的上面。
- POPUP_LAYER
- 彈出層顯示在對(duì)話框的上面。這樣,與組合框、工具提示和其他幫助文本關(guān)聯(lián)的彈出式窗口將出現(xiàn)在組件、調(diào)色板或生成它們的對(duì)話框之上。
- DRAG_LAYER
- 拖動(dòng)一個(gè)組件時(shí),將該組件重分配到拖動(dòng)層可確保將其定位在容器中的其他所有組件之上。完成拖動(dòng)后,可將該組件重分配到其正常層。
可以使用 JLayeredPane
的方法 moveToFront(Component)
、moveToBack(Component)
和 setPosition
在組件所在層中對(duì)其進(jìn)行重定位。還可以使用 setLayer
方法更改該組件的當(dāng)前層。
詳細(xì)信息
JLayeredPane
以類(lèi)似 Container
的方式管理其子級(jí)列表,但允許在其內(nèi)部定義多個(gè)層。對(duì)同一層中子級(jí)的管理就像普通的 Container
對(duì)象一樣,但添加的功能是,當(dāng)子組件重疊時(shí),高層中的子組件顯示在低層中的子組件之上。
每一層都是一個(gè)不同的整數(shù)。可以在調(diào)用 add 的過(guò)程中通過(guò)傳遞 Integer
對(duì)象,從而在 Component
上設(shè)置 layer 屬性。
例如:
layeredPane.add(child, JLayeredPane.DEFAULT_LAYER);
或者
layeredPane.add(child, new Integer(10));
還可以通過(guò)在 JLayeredPane
上進(jìn)行如下調(diào)用在 Component 上設(shè)置 layer 屬性:
layeredPaneParent.setLayer(child, 10)
JLayeredPane
是該 Component 的父組件。應(yīng)該將子組件添加到父組件之前 設(shè)置 layer 屬性。
編號(hào)較高的層顯示在編號(hào)較低的層之上。因此,對(duì)于每個(gè)組件,使用其層編號(hào)和字母即可,有代表性的列表順序如下所示:
5a, 5b, 5c, 2a, 2b, 2c, 1a
其中最左邊的組件最接近顯示區(qū)的頂部。
可以通過(guò)調(diào)用 moveToFront
或 moveToBack
將組件移入到其所在層的頂部或底部位置。
還可以直接指定某層中組件的位置。有效的位置范圍是從 0 到該層中組件數(shù)減一所得的值。值 -1 指示最底層位置。值 0 指示最頂層位置。與層的編號(hào)不同,較高的位置值顯示在較低 處。
注: 此序列(通過(guò) java.awt.Container 定義)與層的編號(hào)序列相反。可是通常使用的是 moveToFront
、moveToBack
和 setLayer
方法。
以下是使用方法 add(Component, layer, position) 的一些示例:調(diào)用 add(5x, 5, -1) 得到:
5a, 5b, 5c, 5x, 2a, 2b, 2c, 1a
調(diào)用 add(5z, 5, 2) 得到:
5a, 5b, 5z, 5c, 5x, 2a, 2b, 2c, 1a
調(diào)用 add(3a, 3, 7) 得到:
5a, 5b, 5z, 5c, 5x, 3a, 2a, 2b, 2c, 1a
使用正常的 paint/event 機(jī)制會(huì)使 1a 出現(xiàn)在底部,5a 出現(xiàn)在所有其他組件之上。
注: 這些層只是一個(gè)邏輯構(gòu)造,LayoutManager 將影響此容器的所有子組件,而不管其層設(shè)置如何。
下面是一個(gè)使用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;
}
}