windows SetCursor 在鼠标移动后恢复

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/169155/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-15 11:23:26  来源:igfitidea点击:

SetCursor reverts after a mouse move

windowsuser-interface

提问by Joe Ludwig

I am using SetCursor to set the system cursor to my own image. The code looks something like this:

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

// member on some class
HCURSOR _cursor;

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

// in some function
SetCursor(_cursor);

When I do this the cursor does change, but on the first mouse move message it changes back to the default system arrow cursor. This is the only code in the project that is setting the cursor. What do I need to do to make the cursor stay the way I set it?

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

回答by Joe Ludwig

It seems that I have two options. The first is the one that Mark Ransom suggested here, which is to respond to the windows WM_SETCURSORmessage and call SetCursor at that time based on where the mouse is. Normally windows will only send you WM_SETCURSORwhen the cursor is over your window, so you would only set the cursor in your window.

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

The other option is to set the default cursor for the window handle at the same time as I call SetCursor. This changes the cursor set by the default handler to WM_SETCURSOR. That code would look something like this:

另一个选项是在我调用SetCursor. 这会将默认处理程序设置的光标更改为WM_SETCURSOR。该代码如下所示:

// defined somewhere
HWND windowHandle;
HCURSOR cursor;

SetCursor(cursor);
SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor);

If you use the second method you have to call both SetCursorand SetClassLongor your cursor will not update until the next mouse move.

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

回答by Mark Ransom

You need to respond to the Windows message WM_SETCURSOR.

您需要响应 Windows 消息WM_SETCURSOR

回答by LarryF

You need to make your HCURSOR handle not go out of scope. When the mouse moves, windows messages start flying all over the place, and it will wipe out your handle (in the example above).

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

Make an HCURSOR a private member of the class, and use that handle when you call LoadCursor...() and SetCursor(). When you are done, do not forget to free it, and clean it up, or you will end up with a resource leak.

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

回答by Heinz Traub

This behavior is intended to be this way. I think the most simple solution is: When creating your window class (RegisterClass || RegisterClassEx), set the WNDCLASS.hCursor || WNDCLASSEX.hCursormember to NULL.

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

回答by sergiol

As @Heinz Traub said the problem comes from the cursor defined on the RegisterClassor RegisterClassExcall. You probably have code like:

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

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;
}

where the wndcls.hCursorsays what cursor will be used when WM_SETCURSORmessage is thrown; it happens every time it occurs a mouse move and not only.

哪里wndcls.hCursor表示WM_SETCURSOR抛出消息时将使用什么游标;每次发生鼠标移动时都会发生这种情况,而不仅仅是。

I solved a similar problem this way:

我以这种方式解决了类似的问题:

In the class' message map add an entry for the WM_SETCURSORmessage:

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

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

Add the method OnSetCursor, which will override the parent class' implementation:

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

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

    return __super::OnSetCursor(pWnd, nHitTest, message);
}

Explanation: when SomeCondition()is true, you will not call parent's implementation. May be you want always to have a cursor not superseded with parent class behavior, so you just need an even shorter method:

说明:当SomeCondition()为真时,您将不会调用父级的实现。可能您希望始终拥有一个不被父类行为取代的游标,所以您只需要一个更短的方法:

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

And the declaration of the method in the header file is:

而头文件中方法的声明是:

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