本文回顧《Thinking in Java》經典範例,展示 Java 1.1 新事件模型如何改寫舊版程式碼,涵蓋 TextField、TextArea、Checkbox/RadioButton、Choice、List、Menu、Dialog、FileDialog 等核心元件,並示範 Applet/Application 雙模式啟動技巧。
// TextNew.java 關鍵片段
t1.addTextListener(new T1()); // 文字改變 → 複製到 t2
t1.addActionListener(new T1A()); // Enter 鍵 → t3 顯示動作計數
t1.addKeyListener(new T1K()); // 按鍵攔截 → 強制大寫、自訂 Backspace
KeyListener 先於 TextListener 觸發,故 T1K 的 e.consume() 能阻止原字元輸入,實現強制大寫。KeyAdapter 避免實作所有介面方法,只覆寫 keyTyped()。t1, t2, t3),無需額外傳參,解決「回調」問題。Java 1.1 新增建構子參數控制捲軸:
new TextArea("t3", 1, 30, TextArea.SCROLLBARS_NONE);
new TextArea("t4", 10, 10, TextArea.SCROLLBARS_VERTICAL_ONLY);
new TextArea("t5", 4, 30, TextArea.SCROLLBARS_HORIZONTAL_ONLY);
new TextArea("t6", 10, 10, TextArea.SCROLLBARS_BOTH);
注意:捲軸只能在建構時決定,運行期無法切換;即使無捲軸,游標移動仍受限制。
class ILCheck implements ItemListener {
public void itemStateChanged(ItemEvent e) {
for (int i=0; i<cb.length; i++)
if (e.getSource().equals(cb[i])) { t.setText("Check box "+(i+1)); return; }
}
}
優點:動態增減核取方塊無需修改監聽器邏輯。
class IL4 implements ItemListener { public void itemStateChanged(ItemEvent e) { t.setText("Radio button four"); } }
優點:邏輯簡單、無條件判斷;缺點:類別數量隨元件增加。
建議:邏輯統一用共用監聽器;邏輯差異大用獨立監聽器。
c.addItemListener(new CL()); // 選擇改變 → 顯示索引與字串
b.addActionListener(new BL()); // 按鈕 → 動態新增項目
已知缺陷:首次下拉前若未加完所有項目,下拉寬度不會自動調整(Java 1.1 行為)。
Java 1.0 List 單擊/雙擊衝突;1.1 直接支援 ItemListener,單選/多選皆自然觸發 itemStateChanged,無需特殊邏輯。
MenuItem 用 ActionListener,CheckboxMenuItem 用 ItemListener。setActionCommand() 解決國際化問題:程式碼檢查命令字串而非標籤文字,修改語言無需改邏輯。MenuShortcut(KeyEvent.VK_E) 為「離開」設定 Ctrl+E 快捷鍵。setMenuBar(mb2)。WINDOW_CLOSING 事件關閉視窗:dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING))。ToeDialog 包含 ToeButton (extends Canvas),四層內部類巢狀。ToeButton 持有父對話框參考存取 turn 狀態。MouseAdapter 簡化滑鼠事件處理。
靜態成員不可置於內部類;非靜態內部類隱含外部實例參考,影響序列化與重用,權衡複雜度與封裝性。
// 開啟模式 (預設)
FileDialog d = new FileDialog(this, "Open?", FileDialog.LOAD);
d.setFile("*.java"); d.setDirectory("."); d.show();
// 儲存模式
FileDialog d = new FileDialog(this, "Save?", FileDialog.SAVE);
getFile() 回傳 null 表示使用者取消。
public static void main(String[] args) {
MyApplet applet = new MyApplet();
Frame f = new Frame("Title");
f.addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent e) { System.exit(0); }
});
f.add(applet, BorderLayout.CENTER);
f.setSize(300,200);
applet.init(); applet.start();
f.setVisible(true); // Java 1.1 取代 show()
}
內部類 WL extends WindowAdapter 可進一步簡化為匿名類別。
jar cf MyApplet.jar *.class
<applet code="MyApplet.class" archive="MyApplet.jar" width=200 height=150></applet>
壓縮傳輸、單一請求、避免類別碎片化。