鼠标移动后,SetCursor恢复

时间:2008-10-03 22:32:56

标签: windows user-interface

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

// member on some class
HCURSOR _cursor;

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

// in some function
SetCursor(_cursor);

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

5 个答案:

答案 0 :(得分:10)

似乎我有两种选择。第一个是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,否则在下一次鼠标移动之前,光标将不会更新。

答案 1 :(得分:5)

您需要回复Windows消息WM_SETCURSOR

答案 2 :(得分:2)

你需要让你的H​​CURSOR手柄不要超出范围。当鼠标移动时,窗口消息开始飞到整个地方,它将擦除你的手柄(在上面的例子中)。

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

答案 3 :(得分:1)

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

答案 4 :(得分:0)

正如@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);