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

VC++ 新手必學:SDI 視圖中顯示 BMP 圖片 (GDI 入門實戰)

     編輯:VC 教學

前言

VB 的 LoadPicture 一行搞定圖片顯示,VC++ 需手動操作 GDI 對象。本文以最經典的 SDI 應用精靈生成的框架 為例,手把手教你在 OnDraw 中繪製位圖,並解析每一步的 GDI 邏輯。

一、資源準備

  1. 創建 MFC SDI 應用程式,全部默認設置。
  2. 資源視圖 → 右鍵 Import → 選擇 BMP 文件導入。
  3. 使用默認資源 ID (如 IDB_BITMAP1),**勿嘗試編輯位圖** (編輯器不支持 >256 色)。

二、核心代碼:OnDraw 實現

void CMyView::OnDraw(CDC* pDC) {
    CMyDoc* pDoc = GetDocument();
    ASSERT_VALID(pDoc);
    if (!pDoc) return;

    // 1. 獲取客戶區矩形 (用於拉伸繪製)
    CRect rect;
    GetClientRect(&rect); // 注意:用 ClientRect 而非 WindowRect

    // 2. 創建記憶體 DC (兼容螢幕 DC)
    CDC memDC;
    memDC.CreateCompatibleDC(pDC);

    // 3. 載入位圖資源
    CBitmap bmp;
    bmp.LoadBitmap(IDB_BITMAP1); // 資源 ID

    // 4. 選入位圖,保存舊對象
    CBitmap* pOldBitmap = memDC.SelectObject(&bmp);

    // 5. 位塊傳輸:將記憶體 DC 內容複製到螢幕 DC
    // 參數:目標左上 (0,0)、寬高、源 DC、源左上 (0,0)、光柵操作
    pDC->BitBlt(0, 0, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY);

    // 6. 恢復記憶體 DC 狀態 (關鍵:防止 GDI 物件洩漏)
    memDC.SelectObject(pOldBitmap);
    // bmp、memDC 析構時自動釋放 GDI 物件
}

三、關鍵步驟圖解與原理解析

步驟API/成員作用類比
1GetClientRect獲取繪製目標區域大小畫布尺寸
2CreateCompatibleDC創建與螢幕兼容的記憶體 DC離屏畫布
3CBitmap::LoadBitmap從資源加載位圖到 GDI 物件載入圖片素材
4SelectObject將位圖關聯到記憶體 DC,返回舊位圖指針裝上畫布
5BitBlt像素級複製 (SRCCOPY: 直接複製)蓋章印刷
6SelectObject(pOld)卸載位圖,恢復 DC 初始狀態卸下畫布

四、進階變體:StretchBlt 實現圖片自適應縮放

若位圖尺寸與視圖不一致,需拉伸填滿:

// 獲取位圖原始尺寸
BITMAP bmInfo;
bmp.GetBitmap(&bmInfo);

// 拉伸繪製:目標區域 = 客戶區,源區域 = 位圖原始尺寸
pDC->StretchBlt(0, 0, rect.Width(), rect.Height(),
                &memDC, 0, 0, bmInfo.bmWidth, bmInfo.bmHeight, SRCCOPY);

缺點:StretchBlt 最近鄰插值,縮放質量差 (鋸齒、馬賽克)。高質量縮放請參考 SetStretchBltMode(HALFTONE) 或 GDI+ / DrawDib 方案。

五、常見坑與調試技巧

  • 資源 ID 錯誤:檢查 resource.h 確認 IDB_BITMAP1 定義存在。
  • 顏色深度不匹配:16/24/32 位位圖在 256 色模式下顏色失真 → 使用 SetStretchBltMode(pDC->m_hDC, HALFTONE) + SetBrushOrgEx 或改用 DrawDib。
  • GDI 物件洩漏:必須成對調用 SelectObject(pOld),否則位圖無法刪除,導致 GDI 計數耗盡程式崩潰。
  • 調試視覺化:在 BitBlt 前後設置斷點,觀察視窗客戶區像素變化;或使用 GdiSetBatchLimit(1) 強制即時刷新。

六、擴展練習

  1. 添加滾動條支持:重寫 OnHScroll/OnVScroll 修改源偏移量傳給 BitBlt。
  2. 支持透明色:使用 TransparentBlt (需 Msimg32.lib) 或手動掩膜。
  3. 雙緩衝防閃爍:在 OnEraseBkgnd 返回 TRUE,所有繪製在記憶體 DC 完成後一次 BitBlt 到螢幕。
  4. 改用 CImage (ATL/MFC 共享類) 支持 JPEG/PNG/GIF 直接加載:img.Load("pic.jpg"); img.Draw(pDC->m_hDC, rect);

結語

「記憶體 DC + SelectObject + BitBlt」是 Windows GDI 繪圖的「Hello World」核心模式。掌握此流程,即掌握了所有位圖操作、離屏繪製、打印預覽、截圖工具的基因。建議新手反覆練習,直到能閉眼寫出正確的六步驟代碼,並理解每一步的資源所有權轉移邏輯。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved