Java GUI 開發從 AWT 進化到 Swing,Applet 到 JApplet 的遷移不僅是類名變更,更是容器架構、佈局管理、組件模型的根本重構。本文通過對比原始碼級差異,揭示 JApplet 引入 ContentPane、RootPane、GlassPane 分層架構的設計意圖,助力開發者平滑遷移並發揮 Swing 豐富組件優勢。
| 特性 | AWT Applet | Swing JApplet | 影響 |
|---|---|---|---|
| 繼承類 | java.applet.Applet | javax.swing.JApplet | Swing 組件層次根節點 |
| 默認佈局 | FlowLayout (左對齊) | BorderLayout (居中) | 視覺呈現默認行為改變 |
| 容器結構 | 單層容器 | JRootPane → ContentPane/GlassPane/LayeredPane | 支持分層、彈出菜單、模態對話框 |
| 組件添加 | applet.add(component) | contentPane.add(component) | 強制分離內容與裝飾層 |
| 菜單欄支持 | 不支持 | setJMenuBar() | Applet 也能擁有頂級菜單 |
| 雙重緩衝 | 手動實現 | 內建 RepaintManager | 消除閃爍,渲染性能提升 |
import java.applet.Applet;
import java.awt.*;
public class OldApplet extends Applet {
public void init() {
// 默認 FlowLayout,組件靠左排列
Label label = new Label("AWT Applet");
add(label); // 直接添加到 Applet 容器
}
}
import javax.swing.*;
import java.awt.*;
public class NewApplet extends JApplet {
public void init() {
// 1. 獲取內容面板(關鍵差異)
Container contentPane = getContentPane();
// contentPane 默認 BorderLayout,組件居中顯示
// 2. 使用 Swing 組件(J 前綴)
Icon icon = new ImageIcon("swing.gif", "A GIF on Swing");
JLabel label = new JLabel("Swing!", icon, SwingConstants.CENTER);
// 3. 添加到內容面板而非 Applet 本身
contentPane.add(label, BorderLayout.CENTER); // 可省略,默認即 CENTER
// 4. 可選:設置菜單欄
JMenuBar menuBar = new JMenuBar();
menuBar.add(new JMenu("File"));
setJMenuBar(menuBar);
}
}
JApplet 唯一子組件是 JRootPane,它包含四層結構:
JApplet
└── JRootPane (唯一子組件)
├── GlassPane (最上層,透明,攔截事件、繪製覆蓋層)
├── LayeredPane (分層面板,管理菜單彈出、工具提示、內部框架 Z 序)
│ └── ContentPane (內容面板,實際業務組件容器,默認 BorderLayout)
└── MenuBar (菜單欄,可選,通過 setJMenuBar 設置)
| 問題現象 | 原因 | 解決方案 |
|---|---|---|
| 組件不顯示/位置錯誤 | 仍用 `applet.add()` 而非 `contentPane.add()` | 全局替換 `add(` → `getContentPane().add(` |
| 佈局失效 | 對 JApplet 調用 `setLayout()` | 改為 `getContentPane().setLayout()` |
| 菜單不顯示 | 用 AWT MenuBar | 改用 `JMenuBar` + `setJMenuBar()` |
| 閃爍嚴重 | 未啟用雙重緩衝 | Swing 默認開啟,檢查是否重寫 `paint()` 破壞機制 |
| 事件無響應 | GlassPane 攔截事件 | 檢查 GlassPane 設置,通常保持默認不可見即可 |