在本章的前部,向我們介紹了老式的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自動地將它們堆積起來。