在一些应用程序中,我注意到一个水平翻转的箭头光标-例如在写字板中,位于段落左侧的水平翻转的箭头光标表示可以选择光标所指向的行。
我的问题是,如何在WinAPI(或MFC)中以编程方式创建此光标?对于这种类型的游标,LoadCursor function似乎没有方便的预定义常量。
预先感谢您的回复。
答案 0 :(得分:2)
您说得对,这是 Windows 应用程序中相当常见的鼠标光标样式。令人费解的是,它并未作为标准游标之一包含在内,这使得应用程序开发人员的工作更加困难。
评论中建议您可以在 Paint 中自己创建此游标(或下载其他人创建的游标),然后将其作为资源包含在您的应用程序二进制文件中,但这有一些非常显着的缺点。它不仅会使您的二进制文件膨胀,而且还意味着您的光标样式本质上是硬编码。默认箭头鼠标光标在 Windows 版本中甚至发生了多次更改,因此您需要在不同版本的“翻转”光标之间进行动态维护和选择,以便与默认光标兼容,更不用说自定义的用户了他们的光标,甚至选择了不同的内置主题(如“反转”)。因此,我强烈建议不要使用这种方法。
正确的解决方案是以编程方式简单地翻转用户的当前箭头光标。这可确保翻转的光标与用户的首选光标样式相匹配。定义如下函数:
/// Creates a cursor that is based on the specified cursor resource (a la LoadCursor),
/// but has been flipped horizontally.
///
/// @param hInstance A handle to an instance of the module whose executable file
/// contains the cursor template.
/// @param pCursorName The name of the template cursor resource to be loaded, or
/// an integer resource created using the MAKEINTRESOURCE macro
/// identifying the cursor to be loaded.
/// @return
/// Returns a handle to the newly-created cursor.
/// @remark
/// Note that the returned cursor must be destroyed when you are finished with it
/// by calling @c DestroyIcon.
/// @remark
/// This function swallows errors, ensuring that some cursor is always returned,
/// even if it has not been flipped. The client could, if desired, modify the
/// implementation to throw exceptions or return NULL in response to errors.
HCURSOR CreateCursorFlipped(HINSTANCE hInstance, LPCTSTR pCursorName)
{
// Load the specified cursor to use as a template.
HCURSOR hCursor = LoadCursor(hInstance, pCursorName);
// Get the underlying bitmaps for the cursor template.
ICONINFO ii;
if (GetIconInfo(hCursor, &ii))
{
// Retrieve information about the bitmap.
BITMAP bm;
if (GetObject(ii.hbmMask, sizeof(bm), &bm) == sizeof(bm))
{
// Create a screen-compatible device context, and draw the cursor bitmaps into
// it, flipped across the X axis, in order to create the new cursor bitmap.
HDC hDC = CreateCompatibleDC(NULL);
if (hDC)
{
HBITMAP hBmpOriginal = (HBITMAP)SelectObject(hDC, ii.hbmMask);
StretchBlt(hDC,
bm.bmWidth - 1,
0,
-bm.bmWidth,
bm.bmHeight,
hDC,
0,
0,
bm.bmWidth,
bm.bmHeight,
SRCCOPY);
if (ii.hbmColor)
{
SelectObject(hDC, ii.hbmColor);
StretchBlt(hDC,
bm.bmWidth - 1,
0,
-bm.bmWidth,
bm.bmHeight,
hDC,
0,
0,
bm.bmWidth,
bm.bmHeight,
SRCCOPY);
}
SelectObject(hDC, hBmpOriginal);
DeleteDC(hDC);
}
// Flip the new cursor's hotspot horizontally.
ii.xHotspot = (bm.bmWidth - 1 - ii.xHotspot);
// Create a new cursor.
HCURSOR hCursorNew = CreateIconIndirect(&ii);
if (hCursorNew)
{
hCursor = hCursorNew;
}
}
// Delete the unneeded bitmaps.
DeleteObject(ii.hbmMask);
if (ii.hbmColor)
{
DeleteObject(ii.hbmColor);
}
}
return hCursor;
}
(如果您使用的是 MFC,那么您可以使用包装类和 RAII 进一步简化此代码。)
得到题中描述的水平翻转箭头光标,用法很简单:
CreateCursorFlipped(nullptr, IDC_ARROW);
但请记住,因为 CreateCursorFlipped
实际上创建了一个新游标(而不是仅仅加载一个系统游标),所以您必须销毁游标通过调用 DestroyIcon
完成使用它。