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

MFC 動態切換游標無閃爍技巧:PreCreateWindow 註冊 NULL 游標類別 + OnMouseMove 即時設定

     編輯:關於VC++

問題現象

覆寫 OnSetCursor() 動態切換游標時,游標會在預設箭頭與自訂游標間閃爍,體驗極差。

根本原因

MFC 預設視窗類別註冊時設定了預設游標 (hCursor)。當滑鼠移動進入視窗,系統先顯示類別預設游標,再呼叫 OnSetCursor 讓你切換,造成「顯示預設 → 切換自訂」兩次繪製 = 閃爍。

解決方案:註冊無游標視窗類別 + OnMouseMove 主動設定

步驟 1:PreCreateWindow 註冊自訂類別,hCursor = NULL


BOOL CMyView::PreCreateWindow(CREATESTRUCT& cs)
{
    if (cs.lpszClass == NULL) {
        // CS_DBLCLKS 支援雙擊,第三參數 hbrBackground = NULL 代表無背景刷 (需自行 OnEraseBkgnd)
        cs.lpszClass = AfxRegisterWndClass(CS_DBLCLKS, NULL, NULL, NULL);
    }
    return CScrollView::PreCreateWindow(cs);
}

關鍵:AfxRegisterWndClass 第四參數 hCursor 傳 NULL,系統不會為此視窗類別設定任何預設游標,徹底消除閃爍來源。

步驟 2:OnMouseMove 根據應用狀態即時設定游標


void CMyView::OnMouseMove(UINT nFlags, CPoint point)
{
    // 根據當前操作模式決定游標
    switch (m_nOperation) {
        case OP_DRAW_LINE:
            ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_CROSS));
            break;
        case OP_SELECT:
            ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
            break;
        case OP_ZOOM:
            ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_SIZENWSE));
            break;
        default:
            ::SetCursor(AfxGetApp()->LoadStandardCursor(IDC_ARROW));
    }
    CScrollView::OnMouseMove(nFlags, point);
}

補充:背景繪製

因視窗類別無背景刷,必須處理 OnEraseBkgnd 避免殘影:


BOOL CMyView::OnEraseBkgnd(CDC* pDC)
{
    CRect rect; GetClientRect(&rect);
    pDC->FillSolidRect(&rect, ::GetSysColor(COLOR_WINDOW));
    return TRUE; // 已處理,不再呼叫預設
}

優缺點比較

方案閃爍複雜度適用場景
OnSetCursor 切換有低單一固定游標
PreCreateWindow NULL + OnMouseMove無中多模式動態游標 (繪圖/編輯/縮放)
SetClassLong GCL_HCURSOR 運行時改類別游標可能中全域切換,影響同類別所有視窗

原始碼下載

MFC SDI 專案示範:繪圖模式 (十字)、選取模式 (箭頭)、縮放模式 (雙向箭頭) 無縫切換,零閃爍。

本文配套源碼

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