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

任意形狀圖形按鈕實現:遮罩繪製、區域裁剪與四態切換完整解析

     編輯:關於VC++

核心原理:MERGEPAINT + SRCAND 雙重遮罩法

Windows 視窗預設為矩形,實現非矩形按鈕需解決兩大問題:

  1. 視覺去背:將圖片透明區域與背景融合。
  2. 命中測試:僅響應圖形實際像素區域的滑鼠事件。

遮罩繪製邏輯

準備兩張同尺寸位圖:

  • 圖 1(彩色圖):背景為白色 (RGB 255,255,255),前景為按鈕實際外觀。
  • 圖 2(遮罩圖):前景區域填黑 (RGB 0,0,0),背景白色。

利用光柵運算特性:

  • ANY_COLOR OR WHITE = WHITE、ANY_COLOR AND WHITE = ANY_COLOR
  • ANY_COLOR OR BLACK = ANY_COLOR、ANY_COLOR AND BLACK = BLACK

繪製序列(關鍵代碼):

if (IsMask) {
    CDC maskDC, memDC, backDC;
    maskDC.CreateCompatibleDC(pDC);  maskDC.SelectObject(&m_MaskBitmap);  // 圖2
    memDC.CreateCompatibleDC(pDC);   memDC.SelectObject(&m_ColorBitmap);  // 圖1

    // 1. 先把主視窗背景畫到按鈕區域(解決按鈕背景≠主視窗背景)
    if (IsBackBmp) {
        backDC.CreateCompatibleDC(pDC);
        backDC.SelectObject(&m_BackBitmap);
        pDC->BitBlt(0,0, w,h, &backDC, backRect.left, backRect.top, SRCCOPY);
    }

    // 2. MERGEPAINT: 遮罩圖反色 OR 目標 → 前景變白、背景保持
    pDC->BitBlt(0,0,w,h, &maskDC, 0,0, MERGEPAINT);
    // 3. SRCAND: 彩色圖 AND 目標 → 前景保留、背景變黑(已被主背景覆蓋)
    pDC->BitBlt(0,0,w,h, &memDC, 0,0, SRCAND);
}
else {
    pDC->BitBlt(0,0,w,h, &memDC, 0,0, SRCCOPY); // 普通模式
}

命中區域構造:BitmapToRegion

採用 Jean-Edouard Lachand-Robert 開源演算法,依指定顏色(遮罩圖的黑色)將位圖轉為 HRGN,再呼叫 SetWindowRgn 讓系統僅在該區域分發滑鼠訊息。

四態圖片支援

SetBitmapId(nOver, nNormal, nPressed, nFocus) 對應滑鼠懸停、正常、按下、擁有焦點四種狀態,DrawItem 根據 DRAWITEMSTRUCT::itemState 選擇對應位圖繪製。

公開介面速查

函式用途關鍵參數
SetMaskBitmapId(id, enable)設定遮罩圖(圖2)資源 ID、啟用旗標
SetBackBmp(bgId, rect)設定主視窗背景圖同步背景資源 ID、按鈕在主視窗 client 矩形
SetRgnMask(maskId, enable)啟用/禁用命中區域遮罩圖資源 ID、旗標
SetBitmapId(over,normal,pressed,focus)四態圖片資源 ID四個資源 ID

使用範例

CRect rc; m_btn.GetWindowRect(rc); ScreenToClient(rc);
m_btn.SetBackBmp(IDB_BACKGROUND, rc);          // 主視窗背景同步
m_btn.SetRgnMask(IDB_OK_MASK, TRUE);           // 構造命中區域
m_btn.SetMaskBitmapId(IDB_OK_MASK, TRUE);      // 遮罩圖
m_btn.SetBitmapId(IDB_BTN_HOVER, IDB_BTN_NORM, // 四態
                  IDB_BTN_DOWN, IDB_BTN_FOCUS);

已知限制與改進方向

  • 高 DPI 下位圖縮放可能導致邊緣鋸齒,建議提供多解析度資源或改用向量繪製。
  • 動態換膚時需同步更新遮罩圖與命中區域。
  • 可整合 CImage/GDI+ 支援 PNG Alpha 通道,簡化遮罩製作流程。

總結

通過「雙重遮罩繪製」解決視覺去背、「BitmapToRegion」解決命中測試,配合四態切換,CControlButton 提供了一個開箱即用的任意形狀按鈕方案。原始碼結構清晰,易於擴展為支援 PNG、高 DPI、動畫幀等現代需求。

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