首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> C語言 >> 關於C語言

啟動畫面特效:隨機積木塊漸顯動畫 (Splash Screen) 實作完整代碼

     編輯:關於C語言

架構設計

  • 衍生 CWnd 建立無標題彈出視窗 (WS_POPUP)。
  • 載入位圖資源,建立記憶體 DC 緩存。
  • WM_PAINT 中執行隨機積木塊動畫:將位圖分割為 N×M 格,隨機順序逐塊 StretchBlt 到螢幕 DC。
  • 動畫完成後可自動關閉或等待主程式初始化完成通知關閉。

類別宣告


class CSplashWnd : public CWnd {
    CDC m_memDC;           // 記憶體 DC 持有位圖
    CBitmap m_bmpSplash;   // 位圖物件
    BITMAP m_bm;           // 位圖尺寸資訊
    CBitmap* m_pOldBmp;    // 記憶體 DC 原位圖
    BOOL m_bAnimating;     // 動畫進行中旗標
public:
    CSplashWnd();
    BOOL Create(UINT nBmpResID); // 建立視窗並載入位圖
    void StartAnimation();       // 觸發動畫 (通常在 OnPaint 首次呼叫)
protected:
    afx_msg void OnPaint();
    afx_msg void OnTimer(UINT_PTR nIDEvent);
    DECLARE_MESSAGE_MAP()
};

建立與初始化


CSplashWnd::CSplashWnd() : m_pOldBmp(NULL), m_bAnimating(FALSE) {}

BOOL CSplashWnd::Create(UINT nBmpResID) {
    m_bmpSplash.LoadBitmap(nBmpResID);
    m_bmpSplash.GetBitmap(&m_bm);

    // 註冊視窗類別
    CString strClass = AfxRegisterWndClass(0, AfxGetApp()->LoadStandardCursor(IDC_ARROW));
    return CreateEx(0, strClass, _T("Splash"), WS_POPUP | WS_VISIBLE,
        0, 0, m_bm.bmWidth, m_bm.bmHeight, NULL, NULL, NULL);
}

void CSplashWnd::OnPaint() {
    CPaintDC dc(this); // 螢幕 DC

    if (!m_bAnimating) {
        // 首次繪製:建立記憶體 DC,啟動動畫
        m_memDC.CreateCompatibleDC(&dc);
        m_pOldBmp = m_memDC.SelectObject(&m_bmpSplash);
        m_bAnimating = TRUE;
        SetTimer(1, 10, NULL); // 10ms 間隔驅動動畫
    }

    // 動畫由 OnTimer 驅動,這裡僅處理動畫完成後的最終全圖顯示
    if (!m_bAnimating) { // 動畫結束旗標在 OnTimer 中設定
        dc.BitBlt(0, 0, m_bm.bmWidth, m_bm.bmHeight, &m_memDC, 0, 0, SRCCOPY);
    }
}

隨機積木塊動畫核心 (OnTimer)


void CSplashWnd::OnTimer(UINT_PTR nIDEvent) {
    if (nIDEvent != 1) return;

    static int s_grid[20][20] = {0}; // 20x20 格,0=未顯示, 1=已顯示
    static int s_shown = 0;
    const int TOTAL = 20 * 20;

    if (s_shown >= TOTAL) {
        KillTimer(1);
        m_bAnimating = FALSE;
        Invalidate(); // 觸發 OnPaint 顯示完整圖
        return;
    }

    // 尋找下一個未顯示格子 (隨機)
    int x, y;
    do {
        x = rand() % 20;
        y = rand() % 20;
    } while (s_grid[x][y]);

    s_grid[x][y] = 1;
    s_shown++;

    // 計算來源/目標矩形
    int sw = m_bm.bmWidth / 20;
    int sh = m_bm.bmHeight / 20;
    int sx = x * sw;
    int sy = y * sh;

    CClientDC dc(this);
    dc.StretchBlt(sx, sy, sw, sh, &m_memDC, sx, sy, sw, sh, SRCCOPY);
}

清理與關閉


CSplashWnd::~CSplashWnd() {
    if (m_memDC.m_hDC) {
        m_memDC.SelectObject(m_pOldBmp);
        m_memDC.DeleteDC();
    }
    m_bmpSplash.DeleteObject();
}

void CSplashWnd::CloseSplash() {
    KillTimer(1);
    DestroyWindow();
}

主程式整合 (CWinApp::InitInstance)


BOOL CMyApp::InitInstance() {
    // ... 標準初始化 ...

    CSplashWnd* pSplash = new CSplashWnd;
    pSplash->Create(IDB_SPLASH);
    pSplash->CenterWindow();
    pSplash->ShowWindow(SW_SHOW);
    pSplash->UpdateWindow();

    // 執行耗時初始化 (資料庫連線、載入設定、檢查更新...)
    // 期間可呼叫 pSplash->SetMessage(_T("正在載入模組...")) 更新文字 (需擴充)

    // 初始化完成
    pSplash->CloseSplash();
    delete pSplash;

    // ... 建立主框架視窗 ...
    return TRUE;
}

進階特效擴充

  • 淡入/淡出: AlphaBlend 漸變 Alpha 值 (需 32-bit 位圖或建立 Alpha 通道)。
  • 水波/百葉窗/捲軸: 修改 OnTimer 矩形計算邏輯 (按行/列/對角線順序)。
  • 進度文字: 記憶體 DC 上 TextOut 繪製進度文字,再 BitBlt 該區域。
  • 多執行緒: 主執行緒顯示 Splash,工作執行緒初始化,完成 PostMessage 通知關閉。

常見問題

問題解決
動畫閃爍雙緩衝:所有繪圖在記憶體 DC,僅 StretchBlt 單塊到螢幕
位圖資源 ID 找不到#include "resource.h" 在類別頭檔,確認資源編譯進 .res
視窗未置中CenterWindow() 需在 Create 後呼叫
主程式初始化卡死,Splash 無法關閉耗時操作移至工作執行緒,或定期 PeekMessage 處理 Splash 訊息
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved