直接在程序片中安放一個菜單是不可能的(Java 1.0,Java1.1和Swing庫不允許),因為它們是針對應用程序的。繼續,如果您不相信我並且確定在程序片中可以合理地擁有菜單,那麼您可以去試驗一下。程序片中沒有setMenuBar()方法,而這種方法是附在菜單中的(我們會看到它可以合理地在程序片產生一個幀,並且幀包含菜單)。
有四種不同類型的MenuComponent(菜單組件),所有的菜單組件起源於抽象類:菜單條(我們可以在一個事件幀裡擁有一個菜單條),菜單去支配一個單獨的下拉菜單或者子菜單、菜單項來說明菜單裡一個單個的元素,以及起源於MenuItem,產生檢查標志(checkmark)去顯示菜單項是否被選擇的CheckBoxMenuItem。
不同的系統使用不同的資源,對Java和AWT而言,我們必須在源代碼中手工匯編所有的菜單。
//: Menu1.java // Menus work only with Frames. // Shows submenus, checkbox menu items // and swapping menus. import java.awt.*; public class Menu1 extends Frame { String[] flavors = { "Chocolate", "Strawberry", "Vanilla Fudge Swirl", "Mint Chip", "Mocha Almond Fudge", "Rum Raisin", "Praline Cream", "Mud Pie" }; TextField t = new TextField("No flavor", 30); MenuBar mb1 = new MenuBar(); Menu f = new Menu("File"); Menu m = new Menu("Flavors"); Menu s = new Menu("Safety"); // Alternative approach: CheckboxMenuItem[] safety = { new CheckboxMenuItem("Guard"), new CheckboxMenuItem("Hide") }; MenuItem[] file = { new MenuItem("Open"), new MenuItem("Exit") }; // A second menu bar to swap to: MenuBar mb2 = new MenuBar(); Menu fooBar = new Menu("fooBar"); MenuItem[] other = { new MenuItem("Foo"), new MenuItem("Bar"), new MenuItem("Baz"), }; Button b = new Button("Swap Menus"); public Menu1() { for(int i = 0; i < flavors.length; i++) { m.add(new MenuItem(flavors[i])); // Add separators at intervals: if((i+1) % 3 == 0) m.addSeparator(); } for(int i = 0; i < safety.length; i++) s.add(safety[i]); f.add(s); for(int i = 0; i < file.length; i++) f.add(file[i]); mb1.add(f); mb1.add(m); setMenuBar(mb1); t.setEditable(false); add("Center", t); // Set up the system for swapping menus: add("North", b); for(int i = 0; i < other.length; i++) fooBar.add(other[i]); mb2.add(fooBar); } public boolean handleEvent(Event evt) { if(evt.id == Event.WINDOW_DESTROY) System.exit(0); else return super.handleEvent(evt); return true; } public boolean action(Event evt, Object arg) { if(evt.target.equals(b)) { MenuBar m = getMenuBar(); if(m == mb1) setMenuBar(mb2); else if (m == mb2) setMenuBar(mb1); } else if(evt.target instanceof MenuItem) { if(arg.equals("Open")) { String s = t.getText(); boolean chosen = false; for(int i = 0; i < flavors.length; i++) if(s.equals(flavors[i])) chosen = true; if(!chosen) t.setText("Choose a flavor first!"); else t.setText("Opening "+ s +". Mmm, mm!"); } else if(evt.target.equals(file[1])) System.exit(0); // CheckboxMenuItems cannot use String // matching; you must match the target: else if(evt.target.equals(safety[0])) t.setText("Guard the Ice Cream! " + "Guarding is " + safety[0].getState()); else if(evt.target.equals(safety[1])) t.setText("Hide the Ice Cream! " + "Is it cold? " + safety[1].getState()); else t.setText(arg.toString()); } else return super.action(evt, arg); return true; } public static void main(String[] args) { Menu1 f = new Menu1(); f.resize(300,200); f.show(); } } ///:~
在這個程序中,我避免了為每個菜單編寫典型的冗長的add()列表調用,因為那看起來像許多的無用的標志。取而代之的是,我安放菜單項到數組中,然後在一個for的循環中通過每個數組調用add()簡單地跳過。這樣的話,增加和減少菜單項變得沒那麼討厭了。
作為一個可選擇的方法(我發現這很難令我滿意,因為它需要更多的分配)CheckboxMenuItems在數組的句柄中被創建是被稱為安全創建;這對數組文件和其它的文件而言是真正的安全。
程序中創建了不是一個而是二個的菜單條來證明菜單條在程序運行時能被交換激活。我們可以看到菜單條怎樣組成菜單,每個菜單怎樣組成菜單項(MenuItems),chenkboxMenuItems或者其它的菜單(產生子菜單)。當菜單組合後,可以用setMenuBar()方法安裝到現在的程序中。值得注意的是當按鈕被壓下時,它將檢查當前的菜單安裝使用getMenuBar(),然後安放其它的菜單條在它的位置上。
當測試是“open”(即開始)時,注意拼寫和大寫,如果開始時沒有對象,Java發出no error(沒有錯誤)的信號。這種字符串比較是一個明顯的程序設計錯誤源。
校驗和非校驗的菜單項自動地運行,與之相關的CheckBoxMenuItems著實令人吃驚,這是因為一些原因它們不允許字符串匹配。(這似乎是自相矛盾的,盡管字符串匹配並不是一種很好的辦法。)因此,我們可以匹配一個目標對象而不是它們的標簽。當演示時,getState()方法用來顯示狀態。我們同樣可以用setState()改變CheckboxMenuItem的狀態。
我們可能會認為一個菜單可以合理地置入超過一個的菜單條中。這看似合理,因為所有我們忽略的菜單條的add()方法都是一個句柄。然而,如果我們試圖這樣做,這個結果將會變得非常的別扭,而遠非我們所希望得到的結果。(很難知道這是一個編程中的錯誤或者說是他們試圖使它以這種方法去運行所產生的。)這個例子同樣向我們展示了為什麼我們需要建立一個應用程序以替代程序片。(這是因為應用程序能支持菜單,而程序片是不能直接使用菜單的。)我們從幀處繼承代替從程序片處繼承。另外,我們為類建一個構建器以取代init()安裝事件。最後,我們創建一個main()方法並且在我們建的新型對象裡,調整它的大小,然後調用show()。它與程序片只在很小的地方有不同之處,然而這時它已經是一個獨立的設置窗口應用程序並且我們可以使用菜單。