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

Win32 光標(Caret)編程基礎與實戰技巧

     編輯:VC 教學

Caret 核心概念

在 Win32 API 中,Caret(光標) 是一個閃爍的視覺指示器,標識鍵盤輸入焦點位置。每個線程同一時刻只能擁有一個 Caret。窗口獲得鍵盤焦點(WM_SETFOCUS)時創建 Caret,失去焦點(WM_KILLFOCUS)時必須銷毀。

核心 API 函數速查

函數用途關鍵參數/返回值
CreateCaret創建光標hWnd 擁有窗口,hBitmap 位圖句柄(NULL 為矩形),寬高(邏輯單位)
ShowCaret顯示並開始閃爍返回 BOOL,成功非零
HideCaret暫時隱藏(不銷毀)配合 ShowCaret 使用
DestroyCaret徹底銷毀光標釋放系統資源
SetCaretPos設置光標位置客戶區坐標,隱藏狀態下也生效
GetCaretPos獲取當前位置輸出 POINT 結構
GetCaretBlinkTime獲取閃爍半週期毫秒數,完整週期 = 2×返回值
SetCaretBlinkTime設置閃爍半週期參數為半週期毫秒數

創建與顯示 Caret 標準流程

1. 捕獲 WM_SETFOCUS 消息


void CMyWnd::OnSetFocus(CWnd* pOldWnd)
{
    CWnd::OnSetFocus(pOldWnd);

    // 創建實心矩形光標(寬 2px,高 16px)
    // 尺寸建議使用 GetSystemMetrics(SM_CXBORDER/SM_CYBORDER) 適配 DPI
    CreateCaret(NULL, 2, 16); 
    ShowCaret();
}

2. 使用位圖光標(自定義形狀)


void CMyWnd::OnSetFocus(CWnd* pOldWnd)
{
    CWnd::OnSetFocus(pOldWnd);

    // 從資源加載位圖(需預先導入 .bmp 資源,IDB_CARET_BITMAP)
    HBITMAP hBmp = LoadBitmap(AfxGetInstanceHandle(), MAKEINTRESOURCE(IDB_CARET_BITMAP));
    if (hBmp)
    {
        // 位圖模式下寬高參數被忽略
        CreateCaret(hBmp, 0, 0);
        ShowCaret();
    }
}

3. 響應 WM_KILLFOCUS 銷毀


void CMyWnd::OnKillFocus(CWnd* pNewWnd)
{
    HideCaret();      // 先隱藏
    DestroyCaret();   // 再銷毀
    CWnd::OnKillFocus(pNewWnd);
}

進階技巧:跟隨鼠標移動的 Caret

某些特殊場景(如繪圖程序、無障礙輔助)需讓 Caret 跟隨滑鼠:


void CMyWnd::OnMouseMove(UINT nFlags, CPoint point)
{
    // 客戶區坐標直接使用
    SetCaretPos(point.x, point.y);
    
    // 注意:高頻移動時閃爍可能不明顯,靜止片刻後恢復正常閃爍
    CWnd::OnMouseMove(nFlags, point);
}

尺寸計算最佳實踐

為獲得系統標準光標尺寸,推薦使用系統度量指標:


int cx = GetSystemMetrics(SM_CXBORDER); // 邊框寬度,通常 1-2 像素
int cy = GetSystemMetrics(SM_CYBORDER); // 邊框高度
// 文本編輯器常用:寬 = cx,高 = 字體高度
CreateCaret(NULL, cx, fontHeight);

常見錯誤與避坑指南

  • 重複創建不銷毀:每次 WM_SETFOCUS 都創建,WM_KILLFOCUS 未銷毀 → GDI 對象泄漏,系統 Caret 表現異常。
  • 跨線程調用:Caret 綁定創建線程,非 UI 線程調用 API 會失敗。
  • 未處理 WM_KILLFOCUS:窗口失去焦點時未銷毀,導致殘留光標干擾其他窗口。
  • 高 DPI 環境下尺寸錯誤:直接使用像素值而非系統度量指標,導致光標過大/過小。
  • 位圖光標顏色反轉:CreateCaret 對位圖像素取反顯示,設計位圖時需考慮反色效果。

MFC 封裝類對比

MFC 未直接封裝 Caret 類,但 CWnd 提供了成員函數別名:


// 等價於 ::CreateCaret(m_hWnd, ...)
CreateCaret(hBitmap, nWidth, nHeight);
ShowCaret();
HideCaret();
DestroyCaret();
SetCaretPos(point);
GetCaretPos(&point);

使用 MFC 封裝可自動綁定 this 窗口句柄,減少參數傳遞錯誤。

總結

Win32 Caret 機制雖簡單,但涉及焦點生命周期、GDI 資源管理、DPI 適配等關鍵細節。掌握標準創建/銷毀流程、位圖光標製作、系統度量指標應用,能構建專業級文本編輯與交互體驗。現代應用中,複雜輸入法編輯器(IME)組合框、RichEdit 等控件已內建高級 Caret 邏輯,自定義需求通常僅限於特殊繪圖、無障礙或教學演示場景。

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