【问题标题】:How do I display a horizontally-flipped arrow cursor in Windows?如何在 Windows 中显示水平翻转的箭头光标?
【发布时间】:2019-11-09 09:47:12
【问题描述】:

我注意到有几个应用程序使用水平翻转的箭头光标。例如,在 Microsoft Word 和写字板中,出现在段落左侧装订线中的水平翻转箭头光标表示可以选择整行:

我想在我自己的应用程序中显示这个光标。但是,LoadCursor function 似乎没有针对此类游标的预定义常量。

如何在 WinAPI 或 MFC 中以编程方式创建此光标?

【问题讨论】:

  • 您可以使用一些图像编辑器创建自己的光标来加载,就像图标或其他资源一样。
  • 在“画笔”中创建自己的光标 - 这是我想要避免的 :-) 但如果没有更好的方法,我会花时间解决这个问题 ;-)跨度>
  • 没有库存游标,如果你用谷歌搜索 左手游标,现有游标很多。下载地址:forum.cockos.com/showthread.php?t=175387
  • 一种方法是加载 IDC_ARROW 光标并创建一个翻转光标。使用 StretchBlt 反转宽度 + CreateIconIndirect 来创建新光标的测试:Flipped cursor

标签: c++ winapi mfc mouse-cursor


【解决方案1】:

没错,这是 Windows 应用程序中相当常见的鼠标光标样式。令人费解的是,它并未作为标准光标之一包含在内,这使得应用程序开发人员的工作更加困难。

cmets 中建议您可以自己在 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 实际上创建了一个new 光标(而不是仅仅加载一个系统光标),所以您必须在完成使用后销毁该光标调用DestroyIcon

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-08
    • 2022-08-20
    • 1970-01-01
    • 1970-01-01
    • 2020-11-15
    • 2016-06-22
    • 1970-01-01
    相关资源
    最近更新 更多