在本章的前部,向我們介紹了老式的CardLayout,並且注意到我們怎樣去管理我們所有的卡片開關。有趣的是,有人現在認為這是一種不錯的設計。幸運的是,Swing用JTabbedPane對它進行了修補,由JTabbedPane來處理這些卡片,開關和其它的任何事物。對比CardLayout和JTabbedPane,我們會發現驚人的差異。
下面的程序例子十分的有趣,因為它利用了前面例子的設計。它們都是做為JPanel的衍生物來構建的,因此這個程序將安放前面的每個例子到它自己在JTabbedPane的窗格中。我們會看到利用RTTI制造的程序十分的小巧精致:
//: Tabbed.java
// Using tabbed panes
package c13.swing;
import java.awt.*;
import javax.swing.*;
import javax.swing.border.*;
public class Tabbed extends JPanel {
static Object[][] q = {
{ "Felix", Borders.class },
{ "The Professor", Buttons.class },
{ "Rock Bottom", ButtonGroups.class },
{ "Theodore", Faces.class },
{ "Simon", Menus.class },
{ "Alvin", Popup.class },
{ "Tom", ListCombo.class },
{ "Jerry", Progress.class },
{ "Bugs", Trees.class },
{ "Daffy", Table.class },
};
static JPanel makePanel(Class c) {
String title = c.getName();
title = title.substring(
title.lastIndexOf('.') + 1);
JPanel sp = null;
try {
sp = (JPanel)c.newInstance();
} catch(Exception e) {
System.out.println(e);
}
sp.setBorder(new TitledBorder(title));
return sp;
}
public Tabbed() {
setLayout(new BorderLayout());
JTabbedPane tabbed = new JTabbedPane();
for(int i = 0; i < q.length; i++)
tabbed.addTab((String)q[i][0],
makePanel((Class)q[i][1]));
add(tabbed, BorderLayout.CENTER);
tabbed.setSelectedIndex(q.length/2);
}
public static void main(String args[]) {
Show.inFrame(new Tabbed(),460,350);
}
} ///:~
再者,我們可以注意到使用的數組構造式樣:第一個元素是被置放在卡片上的String,第二個元素是將被顯示在對應窗格上JPanel類。在Tabbed()構建器裡,我們可以看到兩個重要的JTabbedPane方法被使用:addTab()插入一個新的窗格,setSelectedIndex()選擇一個窗格並從它開始。(一個在中間被選中的窗格證明我們不必從第一個窗格開始)。
當我們調用addTab()方法時,我們為它提供卡片的String和一些組件(也就是說,一個AWT組件,而不是一個來自AWT的JComponent)。這個組件會被顯示在窗格中。一旦我們這樣做了,自然而然的就不需要更多管理了——JTabbedPane會為我們處理其它的任何事。
makePanel()方法獲取我們想創建的類Class對象和用newInstance()去創建並造型為JPanel(當然,假定那些類是必須從JPanel繼承才能增加的類,除非在這一節中為程序例子的結構所使用)。它增加了一個包括類名並返回結果的TitledBorder,以作為一個JPanel在addTab()被使用。
當我們運行程序時,我們會發現如果卡片太多,填滿了一行,JTabbedPane自動地將它們堆積起來。