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

CEdit 控制項透明化實戰:打造帶圖形背景的編輯框

     編輯:關於VC++

核心難點:CEdit 繪製機制與重繪時機

CEdit 非單純 WM_PAINT 繪製,其重繪觸發點分散:

  • 鍵盤/滑鼠輸入導致內容變更(EN_CHANGE 相關)。
  • 選取範圍變更(滑鼠拖選、Shift+方向鍵)。
  • 系統發送 WM_PAINT。

直接重寫 OnPaint 會破壞內部繪製邏輯,導致顯示異常。正解:**攔截關鍵訊息,強制 CEdit 自行完整重繪**。

關鍵訊息攔截策略

操作觸發訊息序列處理策略
按鍵輸入/刪除GetDlgCode → KeyUp在 OnGetDlgCode 呼叫 RedrawWindow(..., RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW)
滑鼠點擊/拖選GetDlgCode → CaptureChanged / KeyUp同上,OnGetDlgCode 強制重繪
滑鼠按住拖動選取連續 MouseMove僅在 OnLButtonDown 重繪一次,避免高頻 MouseMove 導致閃爍與效能問題

完整實作類別:CTpEdit

標頭檔


class CTpEdit : public CEdit
{
public:
    BOOL m_mousedown = FALSE; // 記錄左鍵按下狀態

protected:
    afx_msg BOOL OnEraseBkgnd(CDC* pDC);
    afx_msg void OnMouseMove(UINT nFlags, CPoint point);
    afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
    afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
    afx_msg UINT OnGetDlgCode();

    DECLARE_MESSAGE_MAP()
};

核心實作


// 強制重繪入口:所有內容/選取變更最終都經過這裡
UINT CTpEdit::OnGetDlgCode()
{
    RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW | RDW_ALLCHILDREN);
    return CEdit::OnGetDlgCode();
}

// 背景透明繪製:配合父視窗 OnCtlColor 設置的 TRANSPARENT 模式
BOOL CTpEdit::OnEraseBkgnd(CDC* pDC)
{
    // 這裡可自訂背景繪製(如貼圖、漸層),若完全透明則直接返回 TRUE
    // 若需自繪背景圖:
    // CBitmap bmp; bmp.LoadBitmap(IDB_BG);
    // CDC memDC; memDC.CreateCompatibleDC(pDC);
    // memDC.SelectObject(&bmp);
    // pDC->BitBlt(0,0,width,height,&memDC,0,0,SRCCOPY);
    return TRUE; // 關鍵:告知系統背景已處理,不再預設填白
}

// 滑鼠拖選優化:按下時重繪一次,移動時不重繪
void CTpEdit::OnLButtonDown(UINT nFlags, CPoint point)
{
    m_mousedown = TRUE;
    RedrawWindow(NULL, NULL, RDW_ERASE | RDW_INVALIDATE | RDW_UPDATENOW);
    CEdit::OnLButtonDown(nFlags, point);
}

void CTpEdit::OnMouseMove(UINT nFlags, CPoint point)
{
    // 拖選過程中不重繪,避免閃爍
    CEdit::OnMouseMove(nFlags, point);
}

void CTpEdit::OnLButtonUp(UINT nFlags, CPoint point)
{
    m_mousedown = FALSE;
    CEdit::OnLButtonUp(nFlags, point);
}

宿主對話框配合:OnCtlColor 設置透明模式


HBRUSH CMyDialog::OnCtlColor(CDC* pDC, CWnd* pWnd, UINT nCtlColor)
{
    HBRUSH hbr = CDialog::OnCtlColor(pDC, pWnd, nCtlColor);
    if (nCtlColor == CTLCOLOR_EDIT && pWnd->GetDlgCtrlID() == IDC_MY_TRANSPARENT_EDIT)
    {
        pDC->SetBkMode(TRANSPARENT);       // 文字輸出透明模式
        pDC->SetTextColor(RGB(255, 0, 0)); // 字體顏色:紅色
        return (HBRUSH)GetStockObject(HOLLOW_BRUSH); // 空心刷,背景完全透明
    }
    return hbr;
}

動態子類化掛載


class CMyDialog : public CDialog
{
    CTpEdit m_tpEdit; // 成員變數

    BOOL OnInitDialog()
    {
        CDialog::OnInitDialog();
        m_tpEdit.SubclassDlgItem(IDC_EDIT_TEMPLATE, this); // 關聯資源模板中的 Edit
        return TRUE;
    }
};

效果總結

  • ✅ 文字輸出無白底,完美疊加於對話框背景圖/漸層之上。
  • ✅ 輸入、刪除、選取、拖選全過程無閃爍、無殘留。
  • ✅ 字體顏色可在 OnCtlColor 動態控制。
  • ✅ 封裝為 CTpEdit 可複用,支援動態建立與 SubclassDlgItem。

本技巧同樣適用於 CRichEditCtrl(需注意其更複雜的繪製流程)。關鍵在於:**尊重 CEdit 內部繪製邏輯,透過 OnGetDlgCode 統一攔截重繪觸發點,配合 RDW_ERASE 觸發 OnEraseBkgnd 實現自定義背景。**

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