圖形使用者介面 (GUI) 是桌面應用的門面。Java 提供 java.awt (AWT) 與 javax.swing (Swing) 兩套工具箱。本文系統梳理架構演進、元件/容器層次、事件委派模型、佈局管理與執行緒規則,助你快速上手桌面開發。
| 維度 | AWT (Abstract Window Toolkit) | Swing |
|---|---|---|
| 發布 | JDK 1.0 | JDK 1.2 (JFC 一部分) |
| 繪製機制 | **Peer 模型**:委派給 OS 原生元件 | **輕量級**:純 Java 繪製,自帶 Look & Feel |
| 跨平台外觀 | 隨 OS 不同(Win/Mac/Linux 各異) | **統一外觀**(Metal/Nimbus/GTK/Windows L&F) |
| 元件豐富度 | 基礎(Button, TextField, Frame) | 豐富(JTable, JTree, JTabbedPane, JSlider...) |
| 效能 | 啟動快,記憶體低 | 啟動稍慢,功能強 |
| 現狀 | 維護模式, Swing 基礎 | 主流桌面選擇(JavaFX 為現代替代) |
關鍵:Swing 元件繼承自 AWT 元件(JButton extends AbstractButton extends JComponent extends Container extends Component),兩者共存互用。
java.awt.Component // 所有元件根類:尺寸、位置、顏色、字型、繪圖
└ java.awt.Container // 容器:可裝載子元件,佈局管理
├ java.awt.Window // 視窗:無邊框/標題列
│ ├ java.awt.Frame // AWT 主視窗
│ └ java.awt.Dialog // 對話框
├ javax.swing.JComponent // Swing 元件基類:雙重緩衝、ToolTip、邊框、鍵盤綁定
│ ├ javax.swing.JPanel // 輕量級容器,佈局基本單位
│ ├ javax.swing.JButton // 按鈕
│ ├ javax.swing.JLabel // 標籤
│ ├ javax.swing.JTextField // 單行輸入
│ ├ javax.swing.JTextArea // 多行文字
│ ├ javax.swing.JTable // 表格
│ └ ... 100+ 元件
└ javax.swing.JFrame // Swing 主視窗(含標題列、選單列、最小/最大/關閉鈕)
Swing 顯層容器(JFrame, JDialog, JApplet, JWindow)、**不可直接** add(component),必須操作**內容窗格**:
JFrame frame = new JFrame("My App");
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
// 方式 1:取得內容窗格加元件
frame.getContentPane().add(new JButton("Click"));
// 方式 2:自建 JPanel 設為內容窗格(推薦,便於佈局)
JPanel panel = new JPanel(new BorderLayout());
panel.add(new JLabel("North"), BorderLayout.NORTH);
panel.add(new JTextArea(), BorderLayout.CENTER);
frame.setContentPane(panel);
frame.pack(); // 依照 preferredSize 自動調整視窗大小
frame.setLocationRelativeTo(null); // 螢幕置中
frame.setVisible(true);
JButton)。ActionEvent, MouseEvent, KeyEvent...)。ActionListener, MouseListener...)的物件。
JButton btn = new JButton("Submit");
// 匿名內部類(Java 7)
btn.addActionListener(new ActionListener() {
@Override public void actionPerformed(ActionEvent e) { doSubmit(); }
});
// Lambda(Java 8+,函數式介面單一方法)
btn.addActionListener(e -> doSubmit());
// 方法參考
btn.addActionListener(this::doSubmit);
| 事件類別 | 監聽器介面 | 核心方法 | 典型來源 |
|---|---|---|---|
| ActionEvent | ActionListener | actionPerformed | Button, MenuItem, Timer, TextField(Enter) |
| MouseEvent | MouseListener / MouseMotionListener | clicked/pressed/released/entered/exited / dragged/moved | 所有 Component |
| KeyEvent | KeyListener | pressed/released/typed | 焦點擁有者 |
| FocusEvent | FocusListener | gained/lost | 所有 Component |
| WindowEvent | WindowListener | opened/closing/closed/iconified/deiconified/activated/deactivated | Window/Frame/Dialog |
| ItemEvent | ItemListener | itemStateChanged | Checkbox, Choice, JComboBox |
介面方法多時(如 MouseListener 5 個),繼承適配器僅覆寫需求:
component.addMouseListener(new MouseAdapter() {
@Override public void mouseClicked(MouseEvent e) { /* 僅處理點擊 */ }
});
| 佈局 | 特徵 | 適用場景 |
|---|---|---|
| FlowLayout | 左右流式換行,預設 JPanel | 簡單工具列、按鈕組 |
| BorderLayout | 五區域,預設 JFrame ContentPane | 主視窗框架 |
| GridLayout | 等分行列網格 | 計算機鍵盤、表單欄位 |
| GridBagLayout | 最強彈性:權重、跨行列、錨點、填充 | 複雜表單、儀表板 |
| BoxLayout | 單向堆疊(X/Y 軸),支援膠水/鋼性區 | 工具列、對話框按鈕區 |
| CardLayout | 卡片疊放,切換顯示 | 精靈嚮導、分頁面板 |
| GroupLayout | IDE 視覺化設計器首選(Matisse/WindowBuilder) | 手寫極難維護 |
// 組合佈局範例:BorderLayout + 內部 JPanel(GridBagLayout)
JPanel center = new JPanel(new GridBagLayout());
GridBagConstraints gbc = new GridBagConstraints();
gbc.insets = new Insets(5,5,5,5); gbc.fill = GridBagConstraints.HORIZONTAL;
gbc.gridx=0; gbc.gridy=0; center.add(new JLabel("Name:"), gbc);
gbc.gridx=1; gbc.weightx=1.0; center.add(new JTextField(20), gbc);
// ...
frame.add(center, BorderLayout.CENTER);
鐵律:所有 Swing 元件建立、修改、查詢必須在 EDT 執行。
// 程式入口:在 EDT 啟動 GUI
SwingUtilities.invokeLater(() -> {
new MyFrame().setVisible(true);
});
// 背景任務完成後更新 UI:回到 EDT
new Thread(() -> {
Data data = heavyLoad();
SwingUtilities.invokeLater(() -> {
tableModel.setData(data); // 安全更新
progressBar.setValue(100);
});
}).start();
// SwingWorker 簡化背景任務 + 進度/結果回傳
new SwingWorker() {
@Override protected Void doInBackground() {
for (int i=0; i<=100; i++) { publish(i); sleep(50); }
return null;
}
@Override protected void process(List chunks) { progressBar.setValue(chunks.get(chunks.size()-1)); }
@Override protected void done() { JOptionPane.showMessageDialog(frame, "Done"); }
}.execute();
javafx.*)。掌握「容器找內容窗格、元件加監聽器、佈局選對策略、更新守 EDT」四句口訣,配合 JPanel 組合佈局與 SwingWorker 非同步任務,即可開發出健壯、美觀的 Java 桌面應用。新專案建議直接拥抱 JavaFX。