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

MDI 客戶區動態背景旗幟:CMdiMainClient 定時器輪播位圖實作

     編輯:關於C語言

應用場景

MDI 應用程式主框架客戶區 (CMDIFrameWnd 內部 CMDIClientWnd) 預設為單色背景。透過衍生 CWnd 類別 CMdiMainClient 接管客戶區繪製,實現位圖輪播動畫背景。

類別核心成員


class CMdiMainClient : public CWnd {
    CBitmap m_bmpBackground;   // 靜態背景 (可選)
    CBitmap m_bmpBanner[8];    // 動畫幀位圖陣列 (資源 IDB_BITMAP0~7)
    int m_nCurrentFrame;       // 當前幀索引
    BOOL m_bStopRotation;      // 暫停旗標
    CSize m_sizeClient;        // 客戶區尺寸
    // ...
};

初始化與資源載入


CMdiMainClient::CMdiMainClient() : m_nCurrentFrame(0), m_bStopRotation(FALSE) {
    VERIFY(m_bmpBackground.LoadBitmap(IDB_BCKGRD)); // 基底背景
    for (int i = 0; i < 8; ++i) {
        VERIFY(m_bmpBanner[i].LoadBitmap(IDB_BITMAP0 + i)); // 動畫幀
    }
}

訊息映射與處理


BEGIN_MESSAGE_MAP(CMdiMainClient, CWnd)
    ON_WM_TIMER()
    ON_WM_ERASEBKGND()
    ON_WM_RBUTTONDOWN() // 右鍵啟動/停止
    ON_WM_LBUTTONDOWN() // 左鍵建立子視窗測試
    ON_WM_SIZE()
END_MESSAGE_MAP()

1. OnEraseBkgnd 繪製當前幀


BOOL CMdiMainClient::OnEraseBkgnd(CDC* pDC) {
    CRect rect; GetClientRect(&rect);

    // 1. 繪製基底背景 (平鋪或拉伸)
    if (m_bmpBackground.GetSafeHandle()) {
        CDC dcMem; dcMem.CreateCompatibleDC(pDC);
        CBitmap* pOld = dcMem.SelectObject(&m_bmpBackground);
        BITMAP bm; m_bmpBackground.GetBitmap(&bm);
        pDC->StretchBlt(0, 0, rect.Width(), rect.Height(), &dcMem, 0, 0, bm.bmWidth, bm.bmHeight, SRCCOPY);
        dcMem.SelectObject(pOld);
    }

    // 2. 繪製動畫幀 (置中或指定位置)
    if (!m_bStopRotation && m_bmpBanner[m_nCurrentFrame].GetSafeHandle()) {
        CDC dcMem; dcMem.CreateCompatibleDC(pDC);
        CBitmap* pOld = dcMem.SelectObject(&m_bmpBanner[m_nCurrentFrame]);
        BITMAP bm; m_bmpBanner[m_nCurrentFrame].GetBitmap(&bm);
        int x = (rect.Width() - bm.bmWidth) / 2;
        int y = (rect.Height() - bm.bmHeight) / 2;
        // 透明繪製需用 TransparentBlt 或遮罩法 (參考前文)
        pDC->BitBlt(x, y, bm.bmWidth, bm.bmHeight, &dcMem, 0, 0, SRCCOPY);
        dcMem.SelectObject(pOld);
    }

    return TRUE; // 已處理背景擦除,系統不再填充實心筆刷
}

2. OnTimer 輪播幀


void CMdiMainClient::OnTimer(UINT_PTR nIDEvent) {
    if (nIDEvent == 1 && !m_bStopRotation) {
        m_nCurrentFrame = (m_nCurrentFrame + 1) % 8;
        Invalidate(FALSE); // 觸發 WM_ERASEBKGND 重繪 (不擦除背景,由我們全繪)
    }
    CWnd::OnTimer(nIDEvent);
}

3. OnSize 同步尺寸與啟動定時器


void CMdiMainClient::OnSize(UINT nType, int cx, int cy) {
    CWnd::OnSize(nType, cx, cy);
    m_sizeClient = CSize(cx, cy);
    if (!m_bStopRotation) {
        SetTimer(1, 300, NULL); // 300ms 換幀 (~3.3 FPS)
    }
}

4. 使用者互動


void CMdiMainClient::OnRButtonDown(UINT nFlags, CPoint point) {
    m_bStopRotation = !m_bStopRotation;
    if (!m_bStopRotation) SetTimer(1, 300, NULL);
    else KillTimer(1);
    CWnd::OnRButtonDown(nFlags, point);
}

void CMdiMainClient::OnLButtonDown(UINT nFlags, CPoint point) {
    // 建立 MDI 子視窗測試動畫持續
    CMDIFrameWnd* pFrame = (CMDIFrameWnd*)GetParent();
    pFrame->MDICreateWindow(...);
    CWnd::OnLButtonDown(nFlags, point);
}

主框架整合


// CMainFrame::OnCreate
if (!m_wndClient.Create(NULL, NULL, WS_CHILD | WS_VISIBLE | WS_CLIPCHILDREN,
    CRect(0,0,0,0), this, AFX_IDW_PANE_FIRST, NULL)) {
    return -1;
}
// m_wndClient 為 CMdiMainClient 成員
// 需在 CMainFrame 建構前設定 m_pClientWnd = &m_wndClient (MFC 內部機制)

或修改 CMainFrame 類別宣告:CMdiMainClient m_wndClient; 並覆寫 GetClientWnd() 返回 &m_wndClient。

優化建議

  • 雙緩衝: OnEraseBkgnd 中建立記憶體 DC 繪製完整幀,再一次 BitBlt 到螢幕,消除閃爍。
  • 透明合成: 動畫幀含透明區需用 TransparentBlt 或遮罩法疊加在基底背景上。
  • 高 DPI: 位圖資源提供多解析度版本,或用 StretchBlt 縮放 (品質下降)。
  • 效能: 位圖預先載入、DC 重用、避免頻繁 CreateCompatibleDC。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved