SetCursor在鼠标移动后恢复

我正在使用SetCursor将系统光标设置为我自己的图像。 代码看起来像这样:

// member on some class HCURSOR _cursor; // at init time _cursor = LoadCursorFromFile("somefilename.cur"); // in some function SetCursor(_cursor); 

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

看来我有两个选择。 第一个是Mark Ransom在这里提出的,它是响应Windows WM_SETCURSOR消息,并根据鼠标的位置调用SetCursor。 当光标位于窗口上时,通常窗口只会向您发送WM_SETCURSOR ,所以您只能将光标放在窗口中。

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

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

如果使用第二种方法,则必须同时调用SetCursorSetClassLong否则直到下一次鼠标移动,光标才会更新。

您需要响应Windows消息WM_SETCURSOR 。

您需要使您的HCURSOR手柄不超出范围。 当鼠标移动时,窗口消息开始在整个地方飞行,并将擦除你的手柄(在上面的例子中)。

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

这种行为是为了这样。 我认为最简单的解决方案是:当创建您的窗口类( RegisterClass || RegisterClassEx ),设置WNDCLASS.hCursor || WNDCLASSEX.hCursor WNDCLASS.hCursor || WNDCLASSEX.hCursor成员为NULL

正如@ 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()为true时,您将不会调用父级的实现。 可能你总是希望游标不会被父类的行为所取代,所以你只需要一个更短的方法:

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

头文件中的方法声明是:

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