【问题标题】:SetCursor reverts after a mouse moveSetCursor 在鼠标移动后恢复
【发布时间】:2010-09-15 05:04:58
【问题描述】:

我正在使用 SetCursor 将系统光标设置为我自己的图像。代码如下所示:

// member on some class
HCURSOR _cursor;

// at init time
_cursor = LoadCursorFromFile("somefilename.cur");

// in some function
SetCursor(_cursor);

当我这样做时,光标确实会改变,但在第一个鼠标移动消息上它会变回默认的系统箭头光标。这是项目中唯一设置光标的代码。我需要做什么才能使光标保持我设置的方式?

【问题讨论】:

    标签: windows user-interface


    【解决方案1】:

    看来我有两个选择。第一个是Mark Ransom这里建议的,就是响应windowsWM_SETCURSOR消息,根据鼠标所在的位置在那个时候调用SetCursor。通常,当光标在您的窗口上时,windows 只会向您发送WM_SETCURSOR,因此您只需将光标设置在您的窗口中。

    另一个选项是在我调用SetCursor 的同时为窗口句柄设置默认光标。这会将默认处理程序设置的光标更改为WM_SETCURSOR。该代码看起来像这样:

    // defined somewhere
    HWND windowHandle;
    HCURSOR cursor;
    
    SetCursor(cursor);
    SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor);
    

    如果您使用第二种方法,您必须同时调用SetCursorSetClassLong,否则您的光标将在下一次鼠标移动之前不会更新。

    【讨论】:

      【解决方案2】:

      您需要回复 Windows 消息WM_SETCURSOR

      【讨论】:

        【解决方案3】:

        您需要使您的 HCURSOR 句柄不超出范围。当鼠标移动时,windows 消息开始飞来飞去,它会清除你的句柄(在上面的例子中)。

        将 HCURSOR 设为类的私有成员,并在调用 LoadCursor...() 和 SetCursor() 时使用该句柄。完成后,不要忘记释放它并清理它,否则最终会导致资源泄漏。

        【讨论】:

          【解决方案4】:

          这种行为是有意为之的。我认为最简单的解决方案是:在创建窗口类(RegisterClass || RegisterClassEx)时,将WNDCLASS.hCursor || WNDCLASSEX.hCursor 成员设置为NULL

          【讨论】:

          • 更改为 NULL 并没有解决问题。光标始终是 而不是普通箭头,而不是允许光标更改。并且始终发送消息 WM_SETCURSOR 消息,因为我可以使用 Spy++ 64 位进行验证。但是,我投了赞成票,因为你让我学到了新东西。
          【解决方案5】:

          正如@Heinz Traub 所说,问题来自RegisterClassRegisterClassEx 调用中定义的光标。你可能有这样的代码:

          BOOL CMyWnd::RegisterWindowClass()
          {
              WNDCLASS wndcls;
              // HINSTANCE hInst = AfxGetInstanceHandle();
              HINSTANCE hInst = AfxGetResourceHandle();
          
              if (!(::GetClassInfo(hInst, _T("MyCtrl"), &wndcls)))
              {
                  // otherwise we need to register a new class
                  wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
                  wndcls.lpfnWndProc      = ::DefWindowProc;
                  wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
                  wndcls.hInstance        = hInst;
                  wndcls.hIcon            = NULL;
                  wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
                  wndcls.hbrBackground    = (HBRUSH) (COLOR_3DFACE + 1);
                  wndcls.lpszMenuName     = NULL;
                  wndcls.lpszClassName    = _T("MyCtrl");
          
                  if (!AfxRegisterClass(&wndcls))
                  {
                      AfxThrowResourceException();
                      return FALSE;
                  }
              }
          
              return TRUE;
          }
          

          wndcls.hCursor表示当WM_SETCURSOR消息被抛出时将使用什么光标;每次发生鼠标移动时都会发生这种情况。

          我用这种方式解决了一个类似的问题:

          在类的消息映射中为WM_SETCURSOR 消息添加一个条目:

          BEGIN_MESSAGE_MAP(CMyWnd, CWnd)
              //... other messages
              ON_WM_SETCURSOR()
          END_MESSAGE_MAP()
          

          添加方法OnSetCursor,它将覆盖父类的实现:

          BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
          {
              if (SomeCondition())
                  return FALSE;
          
              return __super::OnSetCursor(pWnd, nHitTest, message);
          }
          

          说明:当SomeCondition() 为真时,您将不会调用父级的实现。可能您总是希望光标不被父类行为取代,因此您只需要一个更短的方法:

          BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
          {
              return FALSE;
          }
          

          并且头文件中方法的声明是:

          afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-02-01
            • 2016-06-29
            • 1970-01-01
            • 2014-11-29
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多