一、啟動畫面設計要點
- 無標題列、無邊框 → 繼承
JWindow(而非 JFrame)。
- 圖片與視窗同步顯示 → 使用
MediaTracker 等待圖片載入完成。
- 動態更新狀態文字 → 覆寫
paint(Graphics) 繪製圖片與文字。
- 主視窗啟動前關閉啟動畫面 → 另一執行緒跑倒數,時間到
dispose()。
二、核心類別:SplashWindow
public class SplashWindow extends JWindow {
private String statusText = "";
private Image logoImg;
public SplashWindow(JFrame owner) {
super(owner);
// 1. 載入圖片(從 classpath 讀取)
logoImg = Toolkit.getDefaultToolkit().getImage(
ClassLoader.getSystemResource("images/splash.jpg"));
// 2. MediaTracker 同步等待圖片載入
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(logoImg, 0);
try { tracker.waitForAll(); } catch (InterruptedException ignored) {}
// 3. 置中螢幕、依圖片尺寸設定視窗大小
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
setLocation((screen.width - logoImg.getWidth(this)) / 2,
(screen.height - logoImg.getHeight(this)) / 2);
setSize(logoImg.getWidth(this), logoImg.getHeight(this));
}
// 對外更新狀態文字
public void setStatus(String text) {
this.statusText = text;
repaint(); // 觸發 paint()
}
@Override
public void paint(Graphics g) {
super.paint(g);
if (logoImg != null) g.drawImage(logoImg, 0, 0, this);
if (statusText != null && !statusText.isEmpty()) {
g.setColor(Color.RED);
g.drawString(statusText, 240, getHeight() - 250);
}
}
}
三、主視窗整合:MainFrame
public class MainFrame extends JFrame implements Runnable {
private SplashWindow splash;
private void init() throws Exception {
// 1. 啟動 Splash 視窗執行緒
Thread splashThread = new Thread(this);
splashThread.start();
splashThread.join(); // 等待 Splash 顯示完成
// 2. 模擬初始化耗時工作(35 秒),期間更新 Splash 狀態
long start = System.currentTimeMillis();
while (System.currentTimeMillis() - start < 35000) {
int remain = 35 - (int)((System.currentTimeMillis() - start) / 1000);
if (splash != null) splash.setStatus("Waiting " + remain);
Thread.sleep(100); // 降低 CPU 佔用
}
// 3. 關閉 Splash,顯示主視窗
if (splash != null) {
splash.dispose();
splash = null;
}
setVisible(true);
}
@Override
public void run() {
splash = new SplashWindow(this);
splash.setVisible(true);
}
public static void main(String[] args) {
SwingUtilities.invokeLater(() -> {
try { new MainFrame().init(); }
catch (Exception e) { e.printStackTrace(); }
});
}
}
四、關鍵技術點解析
| 技術點 | 作用 |
JWindow | 無裝飾視窗,適合啟動畫面、工具提示等輕量彈出層 |
MediaTracker | 同步追蹤圖片載入狀態,避免視窗顯示後圖片延遲出現 |
repaint() vs paint() | repaint() 排程重繪,paint() 實際繪製邏輯;切勿直接呼叫 paint() |
| 雙執行緒協作 | Splash 顯示執行緒 + 主初始化執行緒,透過 join() 同步 |
dispose() | 釋放原生視窗資源,必須在事件調度執行緒呼叫(本例已在 EDT) |
五、現代化改良建議
- 改用
SwingWorker 執行後台初始化,publish()/process() 更新進度,避免手動 Thread.sleep。
- 圖片資源建議放入模組化 JAR,使用
Class.getResource() 載入。
- 高 DPI 螢幕下圖片需支援
@2x、@3x 多解析度版本。
- Java 9+ 可考慮
JFrame.setOpacity() 實現淡入淡出動畫。