Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/user-interface/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Windows SetCursor在鼠标移动后恢复_Windows_User Interface - Fatal编程技术网

Windows 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

我正在使用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);

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

您需要响应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位验证的那样。然而,我投了更高的票,因为你让我学到了一些新东西。