CEdit 非單純 WM_PAINT 繪製,其重繪觸發點分散:
EN_CHANGE 相關)。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實現自定義背景。**