歡迎來到沒有內容窗格的世界。在研究如何可以不 使用內容窗格之前,讓我們先看一下內容窗格是什麼,以及它為什麼存在。在 Swing 中,所有頂級容器,比如 JFrame、JApplet 和 JDialog,都是由 JRootPane 來內部管理的。但是,為什麼這些幀不自己管理自己呢?根窗格使頂級對象能夠擁有菜單欄、將對象拖到其他組件之上的 glass 窗格,以及一個用於包含所有容器組件的內容窗格。而您要用這個內容窗格來設置布局管理器和添加組件,如圖 1 所示。因為所有的頂級容器都需要相同的對象集合,所以其管理被委派給 JRootPane。
圖 1. JRootPane 容器
老方法
在了解使用內容窗格(或者“令人痛苦的東西”,視情況而定)的新方法之前,讓我們回過頭來看一下在引入 Swing 之前是如何使用內容窗格的。在 5.0 版本之前,無法設置幀的布局管理器或者直接將組件添加到幀中。您必須獲得該幀的內容窗格,用它作為替代。清單 1 中顯示了一般的內容窗格使用流程:
清單 1. 5.0 之前的內容窗格使用情況
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = ...;
JButton button = ...;
Container contentPane = frame.getContentPane();
LayoutManager layout = new GridLayout(1,2);
contentPane.setLayout(layout);
contentPane.add(label);
contentPane.add(button);
內容窗格本身並不難使用,但是編程人員未必總是記得直接處理內容窗格。如果您偶爾想試著更改幀的布局管理器或者在運行期間直接將組件添加到幀中,那麼您將看到以下錯誤:
java.lang.Error: Do not use javax.swing.JFrame.setLayout() use
javax.swing.JFrame.getContentPane().setLayout() instead
這就是所有人都在猜測的,為什麼 Java 平台不夠智能,無法知道您試圖更改幀的布局管理器時實際上是想為內容窗格更改布局管理器。在 5.0 版本之前,您必須記得在做其他任何事之前,要先獲得內容窗格。
使用 Tiger 的方法
通過使用 5.0 版本,Swing 開發人員的生活變得更加輕松。雖然內容窗格仍然存在,但您幾乎不必直接使用它。調用 setLayout()、add() 和 remove() 現在被轉到內容窗格上進行。換句話說,現在不用獲得諸如包含 getContentPane() 的 JFrame 之類的高級容器的內容窗格,然後對其進行操作,而是直接在幀對象上調用 setLayout()、add() 和 remove() 即可。清單 2 顯示了處理幀的新方法:
清單 2. Tiger 技術
JFrame frame = new JFrame("Title");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
JLabel label = ...;
JButton button = ...;
LayoutManager layout = new GridLayout(1,2);
frame.setLayout(layout);
frame.add(label);
frame.add(button);
結束語
指出這樣一點很重要,即內容窗格並沒有從框架中刪除掉,只是您通常不必直接處理它了。為什麼只是說通常,而不是說總是呢?實際上,有時您確實 必須直接處理內容窗格。在幀上調用 setBackground() 無法將該調用傳遞給內容窗格,它只會改變幀的背景。setComponentZOrder() 方法是另一種類似的處理方法。在幀上調用 setComponentZOrder() 將改變幀中的布局。實際上,您真正需要的方法是在內容窗格上調用 setComponentZOrder(),因為它隨後將處理內容窗格中組件的疊置順序(z-order)。