Windows SetCursor在鼠标移动后恢复
我正在使用SetCursor将系统光标设置为我自己的图像。代码如下所示:Windows SetCursor在鼠标移动后恢复,windows,user-interface,Windows,User Interface,我正在使用SetCursor将系统光标设置为我自己的图像。代码如下所示: // member on some class HCURSOR _cursor; // at init time _cursor = LoadCursorFromFile("somefilename.cur"); // in some function SetCursor(_cursor); // defined somewhere HWND windowHandle; HCURSOR cursor; SetCur
// member on some class
HCURSOR _cursor;
// at init time
_cursor = LoadCursorFromFile("somefilename.cur");
// in some function
SetCursor(_cursor);
// defined somewhere
HWND windowHandle;
HCURSOR cursor;
SetCursor(cursor);
SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor);
执行此操作时,光标确实会更改,但在第一条鼠标移动消息中,它会更改回默认的系统箭头光标。这是项目中唯一设置光标的代码。我需要做什么才能使光标保持我设置的方式?您需要响应Windows消息。您需要使您的HCURSOR句柄不超出范围。当鼠标移动时,windows消息开始到处飞,它会擦去你的手柄(在上面的例子中)
使HCURSOR成为类的私有成员,并在调用LoadCursor…()和SetCursor()时使用该句柄。完成后,不要忘了释放它,并将其清理干净,否则将导致资源泄漏。看来我有两个选择。第一个是MarkRansom在这里建议的,它响应windows
WM_SETCURSOR
消息,并根据鼠标所在的位置调用SETCURSOR。通常,当光标位于窗口上方时,windows只会向您发送WM_SETCURSOR
,因此您只会在窗口中设置光标
另一个选项是在调用SetCursor
的同时设置窗口句柄的默认光标。这会将默认处理程序设置的光标更改为WM_SETCURSOR
。该代码看起来像这样:
// member on some class
HCURSOR _cursor;
// at init time
_cursor = LoadCursorFromFile("somefilename.cur");
// in some function
SetCursor(_cursor);
// defined somewhere
HWND windowHandle;
HCURSOR cursor;
SetCursor(cursor);
SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor);
如果使用第二种方法,则必须同时调用
SetCursor
和SetClassLong
,否则直到下一次移动鼠标时,光标才会更新。此行为就是这样设计的。我认为最简单的解决方案是:在创建窗口类(RegisterClass | | RegisterClass
)时,将WNDCLASS.hCursor | | WNDCLASSEX.hCursor
成员设置为NULL
,正如@Heinz Traub所说,问题来自RegisterClass
或RegisterClass
调用上定义的光标。您可能有如下代码:
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);
更改为NULL并不能解决问题。不允许光标更改,而是始终使用光标而不是普通箭头。而且消息WM_SETCURSOR消息总是被发送,正如我可以用Spy++64位验证的那样。然而,我投了更高的票,因为你让我学到了一些新东西。