設計思路
- 使用
JWindow(無標題欄、邊框的容器)作為無模態啟動視窗。
- 主執行緒負責初始化任務,UI 執行緒負責繪製進度條動畫。
MediaTracker 確保圖片完全載入後再顯示,避免畫面閃爍。
核心類別:ESplash
public class ESplash extends JWindow implements Runnable {
private Thread thread;
private Image logo;
private int imageWidth, imageHeight;
public ESplash() {
logo = new ECreateIcon().getSplashImage();
loadImage(logo); // 同步載入
imageWidth = logo.getWidth(this);
imageHeight = logo.getHeight(this);
setBackground(Color.WHITE);
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
setSize(imageWidth + 10, imageHeight + 10);
centerOnScreen();
setVisible(true);
}
private void centerOnScreen() {
Dimension screen = Toolkit.getDefaultToolkit().getScreenSize();
int x = (screen.width - getWidth()) / 2;
int y = (screen.height - getHeight()) / 2;
setLocation(x, y);
}
private void loadImage(Image img) {
MediaTracker tracker = new MediaTracker(this);
tracker.addImage(img, 0);
try { tracker.waitForID(0); }
catch (InterruptedException ignored) {}
}
@Override
public void paint(Graphics g) {
// 繪製 Logo
g.drawImage(logo, 5, 5, imageWidth, imageHeight, this);
// 狀態文字
g.setColor(new Color(102, 102, 150));
g.drawString("正在初始化系統......", 7, getHeight() - 72);
// 進度條背景框
g.setColor(Color.WHITE);
g.fillRect(5, getHeight() - 70, 317, 7);
g.drawRect(5, getHeight() - 70, 317, 7);
// 動態填充進度條(模擬載入過程)
g.setColor(new Color(102, 102, 150));
for (int n = 0; n < 317; n += 5) {
try {
Thread.sleep(50);
g.fillRect(5, getHeight() - 70, n, 5);
} catch (Exception ignored) {}
}
}
@Override
public void run() {
setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
repaint();
}
public void stop() {
thread = null;
logo = null; // 釋放圖片資源
}
@Override
public void update(Graphics g) { paint(g); } // 防止閃爍
}
圖片載入輔助類:ECreateIcon
public class ECreateIcon {
private Image splashImage;
public ECreateIcon() {
splashImage = Toolkit.getDefaultToolkit()
.getImage("resources/images/Esplash.gif");
}
public Image getSplashImage() { return splashImage; }
public ImageIcon createImageIcon(String filename) {
String path = "/resources/images/" + filename;
return new ImageIcon(getClass().getResource(path));
}
}
使用方式
public static void main(String[] args) {
// 1. 顯示 Splash
ESplash splash = new ESplash();
// 2. 模擬耗時初始化(實際替換為 SpringContext 載入、資料庫連線等)
try { Thread.sleep(3000); } catch (InterruptedException e) {}
// 3. 關閉 Splash,啟動主視窗
splash.stop();
new MainFrame().setVisible(true);
}
關鍵點總結
| 技術點 | 實作方式 |
| 無邊框視窗 | JWindow 而非 JFrame |
| 圖片同步載入 | MediaTracker.waitForID() |
| 螢幕置中 | Toolkit.getScreenSize() 計算座標 |
| 進度條動畫 | paint() 中 Thread.sleep 分段填充 |
| 防閃爍 | 覆寫 update() 直接呼叫 paint() |
| 資源釋放 | stop() 中置空 Image 參考 |
Java 6+ 可使用 SplashScreen 類(java.awt.SplashScreen)實現原生級啟動畫面,無需自行繪製,支援命令列參數 -splash:image.png。