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

自繪按鈕進階補完:解決非矩形按鈕「殘角」問題 (CRgn 裁剪 + OnEraseBkgnd 抑制)

     編輯:VC 教學

上一篇《自繪按鈕的實現》打造的 CXPButton 雖美觀,但有一隱藏缺陷:**當對話框背景色非標準灰色時,按鈕四個圓角處會出現難看的方形「殘角」**。本文徹底解決此問題,核心技術:**CRgn::CreateRoundRectRgn 設定非矩形視窗區域 + 重寫 OnEraseBkgnd 返回 TRUE 抑制系統背景繪製**。

問題複現

對話框 OnEraseBkgnd 填藍色背景 (RGB(0,0,255)) 後運行,按鈕四角出現白色方塊殘角:

圖一:藍色背景下按鈕四角出現白色殘角

根因分析

  1. MFC 標準按鈕視窗區域為矩形,DrawItem 僅繪製客戶區內容,四角仍屬視窗區域。
  2. 系統在 WM_ERASEBKGND 時,按矩形區域填充系統色 (COLOR_BTNFACE),形成白角。
  3. DrawItem 繪製圓角矩形雖覆蓋客戶區,但非客戶區 (四角) 已被系統填色,且不在 DrawItem 裁剪區內。

雙管齊下的完美解決方案

步驟一:PreSubclassWindow 中用 CRgn 裁剪視窗區域為圓角矩形

void CXPButton::PreSubclassWindow()
{
    CButton::PreSubclassWindow();
    ModifyStyle(0, BS_OWNERDRAW);

    // 設定視窗有效區域為圓角矩形 (角半徑 5)
    CRgn rgn;
    CRect rc; GetClientRect(&rc);
    rgn.CreateRoundRectRgn(rc.left, rc.top, rc.right, rc.bottom, 5, 5);
    SetWindowRgn(rgn, TRUE); // TRUE=重繪, 系統接管 rgn 生命週期
    // rgn.Detach() 或不呼叫 DeleteObject,所有權已轉移給系統
}

原理: SetWindowRgn 將視窗可見/可點擊區域限制為圓角矩形,四角區域不再屬於視窗,滑鼠點擊穿透,系統也不會繪製。

步驟二:重寫 OnEraseBkgnd 返回 TRUE 徹底禁止系統背景繪製

即使設定區域,系統仍可能在 WM_ERASEBKGND 嘗試填充。直接攔截:

BOOL CXPButton::OnEraseBkgnd(CDC* pDC)
{
    return TRUE; // 告訴系統:「背景我已處理 (實際上在 DrawItem 處理)」,阻止系統填充
}

修復後效果

圖二:殘角消失,按鈕完美融入藍色背景

關鍵知識點補充

  • DrawItem 繪製背景色的前提: 若你知道父視窗背景色,可在 DrawItem 開頭 FillSolidRect 該色,覆蓋系統殘留。但 OnEraseBkgnd 返回 TRUE 更徹底、不依賴父視窗色。
  • ClassWizard 添加虛函數技巧: 右鍵類別 → Add Virtual Function → 列表找 DrawItem、OnEraseBkgnd、PreSubclassWindow 添加。
  • CRgn 類別威力: 支援 CreateRectRgn, CreateRoundRectRgn, CreateEllipticRgn, CreatePolygonRgn, CombineRgn (合併/相交/差集) 等,是構建不規則視窗/控制項的核心工具。建議深入研讀 MSDN 文檔。

練習挑戰:圓形按鈕殘角修復

文章開頭展示的圓形按鈕組同樣存在殘角問題。附件提供練習專案,標註「提示」處待修復。思路相同:CreateEllipticRgn + OnEraseBkgnd 返回 TRUE。歡迎嘗試並分享心得!

練習專案:圓形按鈕殘角修復挑戰

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