正确地在WM_SETCURSOR处理程序中重置游标

Alw*_*uff 5 c++ winapi

介绍及相关资料:

我已经制作了一个应用程序,当鼠标悬停在静态控件上方时,需要将光标的外观更改为手,否则将其重置为普通光标.

我的初始应用程序是全屏模式,但最近条款已更改,并且必须具有可调整大小的窗口.

这意味着WM_SETCURSOR必须重写我的处理程序以反映新引入的更改.

游标被加载WM_CREATE,我已经定义了类游标,如下所示:

   // cursors 
   case WM_CREATE:
      hCursorHand = LoadCursor( NULL, IDC_HAND );
      hCursorArrow = LoadCursor( NULL, IDC_ARROW );
      // other stuff
Run Code Online (Sandbox Code Playgroud)

在我班上:

   WNDCLASSEX wc;
   // ...
   wc.hCursor = hCursorArrow;
   //...
Run Code Online (Sandbox Code Playgroud)

这是我的旧WM_CURSOR处理程序(为简化起见,代码已简化):

   case WM_SETCURSOR:
        if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
             SetCursor(hCursorHand);
        else
             SetCursor(hCursorArrow);
        return TRUE;
Run Code Online (Sandbox Code Playgroud)

如果光标悬停在静态控件之上,那么我的处理程序将其更改为手动,否则将其设置为默认光标(箭头).

Bellow是我在Paint中绘制的图片,当它悬停在静态控件上方时显示所需的光标外观,它位于客户端区域,当用户调整窗口大小时.

在此输入图像描述

如果需要额外的代码片段,请询问,我将编辑我的帖子,但是现在,它们被省略以保持帖子简洁明了.

我在Windows XP上工作,使用MS Visual Studio C++和纯Win32 API.

我努力解决问题:

贝娄是我尝试过的代码片段,但它们都失败了:

第一个片段:

   case WM_SETCURSOR:
        if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
        {
             SetCursor(hCursorHand); 
             return TRUE; 
        }
        else
             return DefWindowProc( hWnd, msg, lParam, wParam );
Run Code Online (Sandbox Code Playgroud)

第二个片段:

   case WM_SETCURSOR:
        if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
        {
             SetCursor(hCursorHand); 
             return TRUE; 
        }
        break; // based on MSDN example
Run Code Online (Sandbox Code Playgroud)

第三个片段:

   case WM_SETCURSOR:
        if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
        {
             SetCursor(hCursorHand); 
             return TRUE; 
        }
        else
             return FALSE;
Run Code Online (Sandbox Code Playgroud)

无论它在哪里,它们都会将光标设置为手.

如果我WM_SETCURSOR保持我的处理程序不变,我得到的唯一问题是,当我将鼠标悬停在边框上时,我会获得常规箭头(如光标的外观),而不是调整箭头大小,但窗口可以调整大小.

如果我注释掉我的WM_SETCURSOR处理程序,大小调整箭头和光标箭头会正确显示,但是当鼠标悬停在静态控件之上时光标不会变成手(这是合乎逻辑的,因为没有WM_SETCURSOR处理程序可以更改它).

我浏览了SO存档,查看了MSDN,CodeProject,DaniWeb,Cprogramming和CodeGuru,但没有成功.

通过这些,我找到了一个例子,人们比较低 lParam命中测试代码.

通过MSDN我找到了命中测试值的链接(http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx),我找到了链接游标类型(http://msdn.microsoft.com/en-us/library/windows/desktop/ms648391%28v=vs.85%29.aspx).

目前我正在阅读它们,因为我认为我将不得不加载额外的游标资源,对命中测试值进行几次比较,然后使用这些资源来相应地设置游标外观.

题:

我真的希望我的WM_SETCURSOR处理程序看起来像这样:

   case WM_SETCURSOR:
        if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
        {
             SetCursor(hCursorHand); 
             return TRUE;
        }
        else
             // reset cursor's look to default
Run Code Online (Sandbox Code Playgroud)

所以我请社区指导我如何做到这一点.

如果这是不可能的,那么我将考虑使用多个if语句来检查命中测试代码,并相应地设置光标的外观.

当然,如果我的问题有更好的解决方案,请提出建议,我也会考虑.

谢谢.

问候.

Jon*_*ter 6

通常,如果您处理WM_SETCURSOR消息,您必须要么

  • 调用SetCursor()设置光标,然后返回TRUE,或
  • 如果消息来自子窗口,则返回FALSE默认处理,或
  • 如果消息来自您自己的窗口,请将消息传递给 DefWindowProc()

我认为MSDN文档中没有明确说明最后两点.

鼠标指针下的窗口获取第一条WM_SETCURSOR消息.如果它处理它并在那时返回,则不会发生任何其他事情.如果它调用DefWindowProc(),则DWP将消息转发到窗口的父级以进行处理.如果父选择不处理它,它可以返回FALSE并且DefWindowProc处理将继续.

但这仅适用于消息来自之前对DWP的调用.如果消息来自窗口本身而不是子节点,则返回TRUEFALSE不设置光标意味着光标将根本不被设置.

另一件事:虽然你的问题没有说明,但我假设您使用GetDlgItem()顶级窗口是一个对话框.如果这是真的,你不能只返回TRUEFALSE留言 - 你需要使用返回值SetWindowLongPtr()并存储返回值DWLP_MSGRESULT.FALSE从对话框程序返回表示您根本没有处理该消息 - 这相当于将消息传递给DefWindowProc().

因此,我认为在您的顶级窗口中正确处理您的情况:

case WM_SETCURSOR:
    if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
    {
        SetCursor(hCursorHand); 
        SetWindowLongPtr(hwnd, DWLP_MSGRESULT, TRUE);
        return TRUE;
    }
    return FALSE;
Run Code Online (Sandbox Code Playgroud)

如果您的顶级窗口实际上不是对话框,您可以这样做:

case WM_SETCURSOR:
    if( (HWND)wParam == GetDlgItem( hwnd, 4000 ) ) 
    {
        SetCursor(hCursorHand); 
        return TRUE;
    }
    return DefWindowProc(hwnd, uMsg, wParam, lParam);
Run Code Online (Sandbox Code Playgroud)