本部分讨论以下主题。
创建游标
以下示例创建两个游标句柄:一个用于标准沙漏游标,一个用于作为应用程序资源定义文件中的资源包含的自定义游标。
HINSTANCE hinst; // handle to current instance
HCURSOR hCurs1, hCurs2; // cursor handles
// Create a standard hourglass cursor.
hCurs1 = LoadCursor(NULL, IDC_WAIT);
// Create a custom cursor based on a resource.
hCurs2 = LoadCursor(hinst, MAKEINTRESOURCE(240));
应用程序应实现自定义游标作为资源,并使用 LoadCursor、 LoadCursorFromFile 或 LoadImage ,而不是在运行时创建游标。 使用游标资源可避免设备依赖、简化本地化,并使应用程序能够共享游标设计。
以下示例使用 CreateCursor 函数在运行时创建自定义单色游标。 此处提供了该示例来说明系统如何解释游标掩码。
HINSTANCE hinst; // handle to current instance
HCURSOR hCurs1, hCurs2; // cursor handles
HCURSOR hCurs3; // cursor handle
// Yin-shaped cursor AND mask (32x32x1bpp)
BYTE ANDmaskCursor[] =
{
0xFF, 0xFC, 0x3F, 0xFF, // ##############----##############
0xFF, 0xC0, 0x1F, 0xFF, // ##########---------#############
0xFF, 0x00, 0x3F, 0xFF, // ########----------##############
0xFE, 0x00, 0xFF, 0xFF, // #######---------################
0xF8, 0x01, 0xFF, 0xFF, // #####----------#################
0xF0, 0x03, 0xFF, 0xFF, // ####----------##################
0xF0, 0x03, 0xFF, 0xFF, // ####----------##################
0xE0, 0x07, 0xFF, 0xFF, // ###----------###################
0xC0, 0x07, 0xFF, 0xFF, // ##-----------###################
0xC0, 0x0F, 0xFF, 0xFF, // ##----------####################
0x80, 0x0F, 0xFF, 0xFF, // #-----------####################
0x80, 0x0F, 0xFF, 0xFF, // #-----------####################
0x80, 0x07, 0xFF, 0xFF, // #------------###################
0x00, 0x07, 0xFF, 0xFF, // -------------###################
0x00, 0x03, 0xFF, 0xFF, // --------------##################
0x00, 0x00, 0xFF, 0xFF, // ----------------################
0x00, 0x00, 0x7F, 0xFF, // -----------------###############
0x00, 0x00, 0x1F, 0xFF, // -------------------#############
0x00, 0x00, 0x0F, 0xFF, // --------------------############
0x80, 0x00, 0x0F, 0xFF, // #-------------------############
0x80, 0x00, 0x07, 0xFF, // #--------------------###########
0x80, 0x00, 0x07, 0xFF, // #--------------------###########
0xC0, 0x00, 0x07, 0xFF, // ##-------------------###########
0xC0, 0x00, 0x0F, 0xFF, // ##------------------############
0xE0, 0x00, 0x0F, 0xFF, // ###-----------------############
0xF0, 0x00, 0x1F, 0xFF, // ####---------------#############
0xF0, 0x00, 0x1F, 0xFF, // ####---------------#############
0xF8, 0x00, 0x3F, 0xFF, // #####-------------##############
0xFE, 0x00, 0x7F, 0xFF, // #######----------###############
0xFF, 0x00, 0xFF, 0xFF, // ########--------################
0xFF, 0xC3, 0xFF, 0xFF, // ##########----##################
0xFF, 0xFF, 0xFF, 0xFF // ################################
};
// Yin-shaped cursor XOR mask (32x32x1bpp)
BYTE XORmaskCursor[] =
{
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x03, 0xC0, 0x00, // --------------####--------------
0x00, 0x3F, 0x00, 0x00, // ----------######----------------
0x00, 0xFE, 0x00, 0x00, // --------#######-----------------
0x03, 0xFC, 0x00, 0x00, // ------########------------------
0x07, 0xF8, 0x00, 0x00, // -----########-------------------
0x07, 0xF8, 0x00, 0x00, // -----########-------------------
0x0F, 0xF0, 0x00, 0x00, // ----########--------------------
0x1F, 0xF0, 0x00, 0x00, // ---#########--------------------
0x1F, 0xE0, 0x00, 0x00, // ---########---------------------
0x3F, 0xE0, 0x00, 0x00, // --#########---------------------
0x3F, 0xE0, 0x00, 0x00, // --#########---------------------
0x3F, 0xF0, 0x00, 0x00, // --##########--------------------
0x7F, 0xF0, 0x00, 0x00, // -###########--------------------
0x7F, 0xF8, 0x00, 0x00, // -############-------------------
0x7F, 0xFC, 0x00, 0x00, // -#############------------------
0x7F, 0xFF, 0x00, 0x00, // -###############----------------
0x7F, 0xFF, 0x80, 0x00, // -################---------------
0x7F, 0xFF, 0xE0, 0x00, // -##################-------------
0x3F, 0xFF, 0xE0, 0x00, // --#################-------------
0x3F, 0xC7, 0xF0, 0x00, // --########----######------------
0x3F, 0x83, 0xF0, 0x00, // --#######------#####------------
0x1F, 0x83, 0xF0, 0x00, // ---######------#####------------
0x1F, 0x83, 0xE0, 0x00, // ---######------####-------------
0x0F, 0xC7, 0xE0, 0x00, // ----######----#####-------------
0x07, 0xFF, 0xC0, 0x00, // -----#############--------------
0x07, 0xFF, 0xC0, 0x00, // -----#############--------------
0x01, 0xFF, 0x80, 0x00, // -------##########---------------
0x00, 0xFF, 0x00, 0x00, // --------########----------------
0x00, 0x3C, 0x00, 0x00, // ----------####------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00 // --------------------------------
};
// Create a custom cursor at run time.
hCurs3 = CreateCursor( hinst, // app. instance
19, // horizontal position of hot spot
2, // vertical position of hot spot
32, // cursor width
32, // cursor height
ANDmaskCursor, // AND mask
XORmaskCursor ); // XOR mask
若要创建游标, CreateCursor 将以下事实表应用于 AND 和 XOR 掩码。
| AND 掩码 | XOR 掩码 | 显示 |
|---|---|---|
| 0 | 0 | 黑色 |
| 0 | 1 | 白色 |
| 1 | 0 | 屏幕 |
| 1 | 1 | 反向屏幕 |
有关详细信息,请参阅 位图。
创建 Alpha 混合光标
按照以下步骤在运行时创建 alpha 混合游标或图标:
- 完成 BITMAPV5HEADER 结构,如下面步骤中的代码示例所示,以定义一个每像素32位的alpha混合DIB。
- 调用 CreateDIBSection 函数,根据已完成 BITMAPV5HEADER 结构创建 DIB 节。
- 使用要用于 alpha 混合游标或图标的位图和 alpha 信息来完成 DIB 部分。
- 完成 ICONINFO 结构。
- 将空的单色位图放置在 hbmMask 字段中,然后将 alpha 混合 DIB 部分置于 hbmColor 字段中。
- 调用 CreateIconIndirect 函数以创建 alpha 混合光标或图标。
以下代码演示如何创建 alpha 混合游标。 通过将 ICONINFO 结构的 fIcon 成员更改为 TRUE,可以使用相同的代码创建 alpha 混合图标:
HCURSOR CreateAlphaCursor(void)
{
HDC hMemDC;
DWORD dwWidth, dwHeight;
BITMAPV5HEADER bi;
HBITMAP hBitmap, hOldBitmap;
void *lpBits;
DWORD x,y;
HCURSOR hAlphaCursor = NULL;
dwWidth = 32; // width of cursor
dwHeight = 32; // height of cursor
ZeroMemory(&bi,sizeof(BITMAPV5HEADER));
bi.bV5Size = sizeof(BITMAPV5HEADER);
bi.bV5Width = dwWidth;
bi.bV5Height = dwHeight;
bi.bV5Planes = 1;
bi.bV5BitCount = 32;
bi.bV5Compression = BI_BITFIELDS;
// The following mask specification specifies a supported 32 BPP
// alpha format for Windows XP.
bi.bV5RedMask = 0x00FF0000;
bi.bV5GreenMask = 0x0000FF00;
bi.bV5BlueMask = 0x000000FF;
bi.bV5AlphaMask = 0xFF000000;
HDC hdc;
hdc = GetDC(NULL);
// Create the DIB section with an alpha channel.
hBitmap = CreateDIBSection(hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS,
(void **)&lpBits, NULL, (DWORD)0);
hMemDC = CreateCompatibleDC(hdc);
ReleaseDC(NULL,hdc);
// Draw something on the DIB section.
hOldBitmap = (HBITMAP)SelectObject(hMemDC, hBitmap);
PatBlt(hMemDC,0,0,dwWidth,dwHeight,WHITENESS);
SetTextColor(hMemDC,RGB(0,0,0));
SetBkMode(hMemDC,TRANSPARENT);
TextOut(hMemDC,0,9,"rgba",4);
SelectObject(hMemDC, hOldBitmap);
DeleteDC(hMemDC);
// Create an empty mask bitmap.
HBITMAP hMonoBitmap = CreateBitmap(dwWidth,dwHeight,1,1,NULL);
// Set the alpha values for each pixel in the cursor so that
// the complete cursor is semi-transparent.
DWORD *lpdwPixel;
lpdwPixel = (DWORD *)lpBits;
for (x=0;x<dwWidth;x++)
for (y=0;y<dwHeight;y++)
{
// Clear the alpha bits
*lpdwPixel &= 0x00FFFFFF;
// Set the alpha bits to 0x9F (semi-transparent)
*lpdwPixel |= 0x9F000000;
lpdwPixel++;
}
ICONINFO ii;
ii.fIcon = FALSE; // Change fIcon to TRUE to create an alpha icon
ii.xHotspot = 0;
ii.yHotspot = 0;
ii.hbmMask = hMonoBitmap;
ii.hbmColor = hBitmap;
// Create the alpha cursor with the alpha DIB section.
hAlphaCursor = CreateIconIndirect(&ii);
DeleteObject(hBitmap);
DeleteObject(hMonoBitmap);
return hAlphaCursor;
}
在关闭之前,必须使用 DestroyCursor 函数销毁使用 CreateCursor 或 CreateIconIndirect 创建的任何游标。 不需要销毁由其他函数创建的游标。
获取游标大小
请参阅 “获取图标大小”。
显示光标
系统会自动显示类游标(与光标指向的窗口关联的游标)。 注册窗口类时,可以分配类游标。 以下示例通过将游标句柄分配给由 wc 参数标识的 WNDCLASS 结构的 hCursor 成员来说明这一点。
WNDCLASS wc;
// Fill the window class structure with parameters that
// describe the main window.
wc.style = NULL; // class style(s)
wc.lpfnWndProc = (WNDPROC) MainWndProc; // window procedure
wc.cbClsExtra = 0; // no per-class extra data
wc.cbWndExtra = 0; // no per-window extra data
wc.hInstance = hinst; // application that owns the class
wc.hIcon = LoadIcon(NULL, IDI_APPLICATION); // class icon
wc.hCursor = LoadCursor(hinst, MAKEINTRESOURCE(230)); // class cursor
wc.hbrBackground = GetStockObject(WHITE_BRUSH); // class background
wc.lpszMenuName = "GenericMenu"; // class menu
wc.lpszClassName = "GenericWClass" // class name
// Register the window class.
return RegisterClass(&wc);
注册窗口类时,应用程序资源定义文件中由 230 标识的游标是基于该类的所有窗口的默认游标。
应用程序可以使用 SetCursor 函数和指定不同的游标句柄来更改游标的设计。 但是,当游标移动时,系统会在新位置重新绘制类游标。 若要防止重新绘制类游标,必须处理 WM_SETCURSOR 消息。 每次未捕获光标移动和鼠标输入时,系统都会将此消息发送到光标移动的窗口。
可以在处理 WM_SETCURSOR时为不同的条件指定不同的游标。 例如,以下示例演示如何在光标移动到最小化应用程序的图标上时显示游标。
case WM_SETCURSOR:
// If the window is minimized, draw the hCurs3 cursor.
// If the window is not minimized, draw the default
// cursor (class cursor).
if (IsIconic(hwnd))
{
SetCursor(hCurs3);
break;
}
当窗口未最小化时,系统将显示类游标。
可以使用 SetClassLong 函数替换类游标。 此函数更改指定类的所有窗口的默认窗口设置。 以下示例将现有类游标替换为 hCurs2 游标。
// Change the cursor for window class represented by hwnd.
SetClassLongPtr(hwnd, // window handle
GCLP_HCURSOR, // change cursor
(LONG_PTR) hCurs2); // new cursor
限制光标
以下示例将光标限制为应用程序的窗口,然后将光标还原到其上一个窗口。 该示例使用 GetClipCursor 函数来记录游标可移动的区域以及 ClipCursor 函数来限制和还原游标。
RECT rcClip; // new area for ClipCursor
RECT rcOldClip; // previous area for ClipCursor
// Record the area in which the cursor can move.
GetClipCursor(&rcOldClip);
// Get the dimensions of the application's window.
GetWindowRect(hwnd, &rcClip);
// Confine the cursor to the application's window.
ClipCursor(&rcClip);
//
// Process input from the confined cursor.
//
// Restore the cursor to its previous area.
ClipCursor(&rcOldClip);
由于系统中一次只有一个游标可用,因此限制游标的应用程序必须在将控件放弃到另一个窗口之前还原游标。
使用游标函数创建捕鼠器
以下示例使用 SetCursorPos、 GetCursorPos、 CreateCursor、 LoadCursor 和 SetCursor 函数创建简单的鼠标跟踪。 它还使用游标和计时器函数每隔 10 秒监视游标的位置。 如果光标位置在过去 10 秒内未更改,并且应用程序的主窗口最小化,则应用程序将更改光标并将其移动到鼠标跟踪图标。
图标中包含一个类似的捕鼠器示例。 它使用 LoadCursor 和 LoadIcon 函数,而不是依赖于设备的 CreateCursor 和 CreateIcon 函数。
HICON hIcon1; // icon handles
POINT ptOld; // previous cursor location
HCURSOR hCurs1; // cursor handle
// The following cursor masks are defined in a code
// example that appears earlier in this section.
// Yin-shaped cursor AND and XOR masks
BYTE ANDmaskCursor[] = ...
BYTE XORmaskCursor[] = ...
// Yang-shaped icon AND mask (32x32x1bpp)
BYTE ANDmaskIcon[] =
{
0xFF, 0xFF, 0xFF, 0xFF, // ################################
0xFF, 0xFF, 0xC3, 0xFF, // ##################----##########
0xFF, 0xFF, 0x00, 0xFF, // ################--------########
0xFF, 0xFE, 0x00, 0x7F, // ###############----------#######
0xFF, 0xFC, 0x00, 0x1F, // ##############-------------#####
0xFF, 0xF8, 0x00, 0x0F, // #############---------------####
0xFF, 0xF8, 0x00, 0x0F, // #############---------------####
0xFF, 0xF0, 0x00, 0x07, // ############-----------------###
0xFF, 0xF0, 0x00, 0x03, // ############------------------##
0xFF, 0xE0, 0x00, 0x03, // ###########-------------------##
0xFF, 0xE0, 0x00, 0x01, // ###########--------------------#
0xFF, 0xE0, 0x00, 0x01, // ###########--------------------#
0xFF, 0xF0, 0x00, 0x01, // ############-------------------#
0xFF, 0xF0, 0x00, 0x00, // ############--------------------
0xFF, 0xF8, 0x00, 0x00, // #############-------------------
0xFF, 0xFC, 0x00, 0x00, // ##############------------------
0xFF, 0xFF, 0x00, 0x00, // ################----------------
0xFF, 0xFF, 0x80, 0x00, // #################---------------
0xFF, 0xFF, 0xE0, 0x00, // ###################-------------
0xFF, 0xFF, 0xE0, 0x01, // ###################------------#
0xFF, 0xFF, 0xF0, 0x01, // ####################-----------#
0xFF, 0xFF, 0xF0, 0x01, // ####################-----------#
0xFF, 0xFF, 0xF0, 0x03, // ####################----------##
0xFF, 0xFF, 0xE0, 0x03, // ###################-----------##
0xFF, 0xFF, 0xE0, 0x07, // ###################----------###
0xFF, 0xFF, 0xC0, 0x0F, // ##################----------####
0xFF, 0xFF, 0xC0, 0x0F, // ##################----------####
0xFF, 0xFF, 0x80, 0x1F, // #################----------#####
0xFF, 0xFF, 0x00, 0x7F, // ################---------#######
0xFF, 0xFC, 0x00, 0xFF, // ##############----------########
0xFF, 0xF8, 0x03, 0xFF, // #############---------##########
0xFF, 0xFC, 0x3F, 0xFF // ##############----##############
};
// Yang-shaped icon XOR mask (32x32x1bpp)
BYTE XORmaskIcon[] =
{
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x38, 0x00, // ------------------###-----------
0x00, 0x00, 0x7C, 0x00, // -----------------#####----------
0x00, 0x00, 0x7C, 0x00, // -----------------#####----------
0x00, 0x00, 0x7C, 0x00, // -----------------#####----------
0x00, 0x00, 0x38, 0x00, // ------------------###-----------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00, // --------------------------------
0x00, 0x00, 0x00, 0x00 // --------------------------------
};
hIcon1 = CreateIcon(hinst, // handle to app. instance
32, // icon width
32, // icon height
1, // number of XOR planes
1, // number of bits per pixel
ANDmaskIcon, // AND mask
XORmaskIcon); // XOR mask
hCurs1 = CreateCursor(hinst, // handle to app. instance
19, // horizontal position of hot spot
2, // vertical position of hot spot
32, // cursor width
32, // cursor height
ANDmaskCursor, // AND mask
XORmaskCursor); // XOR mask
// Fill in the window class structure.
WNDCLASS wc;
wc.hIcon = hIcon1; // class icon
wc.hCursor = LoadCursor(NULL, IDC_ARROW); // class cursor
//
// Register the window class and perform
// other application initialization.
//
// Set a timer for the mousetrap.
GetCursorPos(&ptOld);
SetTimer(hwnd, IDT_CURSOR, 10000, (TIMERPROC) NULL);
LONG APIENTRY MainWndProc(
HWND hwnd, // window handle
UINT message, // type of message
UINT wParam, // additional information
LONG lParam) // additional information
{
HDC hdc; // handle to device context
POINT pt; // current cursor location
RECT rc; // minimized window location
switch (message)
{
//
// Process other messages.
//
case WM_TIMER:
// If the window is minimized, compare the
// current cursor position with the one 10
// seconds before. If the cursor position has
// not changed, move the cursor to the icon.
if (IsIconic(hwnd))
{
GetCursorPos(&pt);
if ((pt.x == ptOld.x) && (pt.y == ptOld.y))
{
GetWindowRect(hwnd, &rc);
SetCursorPos(rc.left + 20, rc.top + 4);
// Note that the additional constants
// (20 and 4) are application-specific
// values to align the yin-shaped cursor
// and the yang-shaped icon.
}
else
{
ptOld.x = pt.x;
ptOld.y = pt.y;
}
}
return 0;
case WM_SETCURSOR:
// If the window is minimized, draw hCurs1.
// If the window is not minimized, draw the
// default cursor (class cursor).
if (IsIconic(hwnd))
{
SetCursor(hCurs1);
break;
}
case WM_DESTROY:
// Destroy timer.
KillTimer(hwnd, IDT_CURSOR);
PostQuitMessage(0);
break;
}
}
使用键盘移动光标
由于系统不需要鼠标,因此应用程序应能够使用键盘模拟鼠标作。 以下示例演示如何通过使用 GetCursorPos 和 SetCursorPos 函数以及处理箭头键的输入来实现此目的。
HCURSOR hCurs1, hCurs2; // cursor handles
POINT pt; // cursor location
RECT rc; // client area coordinates
static int repeat = 1; // repeat key counter
//
// Other declarations and initialization.
//
switch (message)
{
//
// Process other messages.
//
case WM_KEYDOWN:
if (wParam != VK_LEFT && wParam != VK_RIGHT &&
wParam != VK_UP && wParam != VK_DOWN)
{
break;
}
GetCursorPos(&pt);
// Convert screen coordinates to client coordinates.
ScreenToClient(hwnd, &pt);
switch (wParam)
{
// Move the cursor to reflect which
// arrow keys are pressed.
case VK_LEFT: // left arrow
pt.x -= repeat;
break;
case VK_RIGHT: // right arrow
pt.x += repeat;
break;
case VK_UP: // up arrow
pt.y -= repeat;
break;
case VK_DOWN: // down arrow
pt.y += repeat;
break;
default:
return 0;
}
repeat++; // Increment repeat count.
// Keep the cursor in the client area.
GetClientRect(hwnd, &rc);
if (pt.x >= rc.right)
{
pt.x = rc.right - 1;
}
else
{
if (pt.x < rc.left)
{
pt.x = rc.left;
}
}
if (pt.y >= rc.bottom)
pt.y = rc.bottom - 1;
else
if (pt.y < rc.top)
pt.y = rc.top;
// Convert client coordinates to screen coordinates.
ClientToScreen(hwnd, &pt);
SetCursorPos(pt.x, pt.y);
return 0;
case WM_KEYUP:
repeat = 1; // Clear repeat count.
return 0;
}