在WM_SETCURSOR处理程序中正确重置光标 [英] Reset cursor in WM_SETCURSOR handler properly

查看:2167
本文介绍了在WM_SETCURSOR处理程序中正确重置光标的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

简介和相关信息:



我已经创建了一个应用程序,当鼠标悬停在静态控件上方时需要将光标的外观改为手动,



我的初始应用程序是在全屏模式,但最近的条款已更改,它必须有一个可调整大小的窗口。



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



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

  // cursors 
case WM_CREATE:
hCursorHand = LoadCursor(NULL,IDC_HAND);
hCursorArrow = LoadCursor(NULL,IDC_ARROW);
//其他东西

在我的课程:

  WNDCLASSEX wc; 
// ...
wc.hCursor = hCursorArrow;
// ...

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

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

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



Bellow是我在Paint中绘制的图片,当它在鼠标悬停在静态控件上方时显示光标所需的外观,和用户调整窗口大小时。



>



如果需要额外的代码片段,请问,我将编辑我的帖子,但现在,他们被省略,以保持简短和简洁。



我在Windows XP上使用MS Visual Studio C ++和纯Win32 API。



我的努力来解决问题:



Bellow是我试过的代码段,但他们都失败了:



第一个片段:

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

第二个代码段:

  case WM_SETCURSOR:
if((HWND)wParam == GetDlgItem(hwnd,4000))
{
SetCursor(hCursorHand);
return TRUE;
}
break; //基于MSDN示例

第三个代码片段:

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

这些设置光标到手,无论它在哪里。



如果我把 WM_SETCURSOR 处理程序保持不变,我得到的唯一问题是,而不是调整箭头,我得到常规箭头



如果我注释了我的 WM_SETCURSOR 处理程序,调整箭头和光标箭头正常出现,但是当光标悬停在静态控件上方(这是逻辑的,因为没有 WM_SETCURSOR 处理程序来改变它),光标不会改变。 >

我浏览了SO archive,看过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 )。



目前我正在阅读他们,因为我认为我将不得不加载额外的游标资源,采取几个比较的命中测试值,然后使用这些资源设置光标相应地看。



QUESTION :



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

  case WM_SETCURSOR:
if((HWND)wParam == GetDlgItem(hwnd,4000))
{
SetCursor(hCursorHand) ;
return TRUE;
}
else
//将光标的外观重置为默认值

所以我请社区指导我如何做这个。



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



当然,如果有更好的解决方案,

谢谢。



回答。

$ b $一般来说,如果您处理 WM_SETCURSOR 消息,您必须

$ b $

b

  • 调用 SetCursor()设置游标,并返回 TRUE

  • 如果邮件来自子窗口,请返回 FALSE 进行默认处理,或

  • 如果消息来自您自己的窗口,请将消息传递到 DefWindowProc()



我认为最后两点在MSDN文档中没有明确。



鼠标指针下的窗口获得第一个 WM_SETCURSOR 邮件。如果它处理它并返回在那一点,没有其他事情发生。然而,如果它调用 DefWindowProc(),那么DWP将消息转发到窗口的父级处理。如果父项选择不处理它,它可以返回 FALSE ,并且DefWindowProc处理将继续。



仅在消息来自之前对DWP的调用时应用。如果消息来源于窗口本身而不是子元素,返回 TRUE FALSE 而不设置光标意味着



另一件事:虽然你的问题没有指定,我假设你使用 GetDlgItem ()您的顶级窗口是一个对话框。如果这是真的,你不能只为一个消息返回 TRUE FALSE - 您需要返回值使用 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;

如果你的顶级窗口实际上不是对话框, p>

  case WM_SETCURSOR:
if((HWND)wParam == GetDlgItem(hwnd,4000))
b $ b SetCursor(hCursorHand);
return TRUE;
}
return DefWindowProc(hwnd,uMsg,wParam,lParam);


INTRODUCTION AND RELEVANT INFORMATION:

I have made an application that needs to change the look of a cursor into hand when mouse hovers above the static control, but resets it to a normal cursor otherwise.

My initial application was in full screen mode, but recently terms have changed and it must have a resizable window.

This means that my handler for WM_SETCURSOR must be rewritten to reflect newly introduced changes.

Cursors are loaded in WM_CREATE, and I have defined class cursor, like this:

   // cursors 
   case WM_CREATE:
      hCursorHand = LoadCursor( NULL, IDC_HAND );
      hCursorArrow = LoadCursor( NULL, IDC_ARROW );
      // other stuff

In my class:

   WNDCLASSEX wc;
   // ...
   wc.hCursor = hCursorArrow;
   //...

This is my old WM_CURSOR handler ( code is simplified for clarity purposes ):

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

If cursor hovers above static control, then my handler changes it to hand, else sets it to default cursor ( arrow ).

Bellow is the picture I have sketched in Paint that displays the desired look of the cursor when it hovers above static control, it is on the client area, and when user resizes window.

If additional code snippets are required, ask and I will edit my post, but for now, they are omitted to keep the post short and concise.

I work on Windows XP, using MS Visual Studio C++ and pure Win32 API.

MY EFFORTS TO SOLVE PROBLEM:

Bellow are the code snippets that I have tried, but they all failed:

First snippet:

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

Second Snippet:

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

Third snippet:

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

These set cursor to hand no matter where it is.

If I leave my WM_SETCURSOR handler unchanged, the only problem I get is that instead of sizing arrows, I get regular arrow ( as the cursor’s look ) when I hover over the border, but window can be sized.

If I comment out my WM_SETCURSOR handler, sizing arrows and cursor arrow appear properly, but cursor doesn’t change into hand when hovers above static control ( which is logical, since there is no WM_SETCURSOR handler to change it ).

I have browsed through SO archive, looked on MSDN, CodeProject , DaniWeb, Cprogramming and CodeGuru, but had no success.

Looking through those, I have found an example where people compare low word of the lParam against hit test code.

Looking through MSDN I have found link for hit test values ( http://msdn.microsoft.com/en-us/library/windows/desktop/ms645618%28v=vs.85%29.aspx ) and I have found link for cursor types (http://msdn.microsoft.com/en-us/library/windows/desktop/ms648391%28v=vs.85%29.aspx ).

Currently I am reading them, because I think that I will have to load additional cursor resources, take several comparisons of hit test values, and then use those resources to set cursor look accordingly.

QUESTION:

I really would like my WM_SETCURSOR handler to look like this:

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

so I ask the community to instruct me on how to do this.

If this isn’t possible, then I will consider using multiple if statements to check the hit test code, and set cursor’s look accordingly.

Of course, if there is better solution for my problem, please suggest it, I will consider it as well.

Thank you.

Regards.

解决方案

In general, if you handle the WM_SETCURSOR message you must either

  • Call SetCursor() to set the cursor, and return TRUE, or
  • If the message came from a child window, return FALSE for default processing, or
  • If the message is from your own window, pass the message through to DefWindowProc()

I think the last two points aren't made quite clear by the MSDN docs.

The window under the mouse pointer gets the first WM_SETCURSOR message. If it handles it and returns at that point, nothing else happens. If however it calls DefWindowProc(), then DWP forwards the message to the window's parent to handle. If the parent chooses not to handle it, it can return FALSE and the DefWindowProc processing will continue.

But this only applies if the message came from a previous call to DWP. If the message originated with the window itself, rather than a child, returning TRUE or FALSE without setting the cursor means the cursor won't be set at all.

Another thing: although your question didn't specify, I'm assuming from your use of GetDlgItem() that your top-level window is a dialog. If that's true, you can't just return TRUE or FALSE for a message - you need to return the value using SetWindowLongPtr() and store the return value in DWLP_MSGRESULT. Returning FALSE from a dialog procedure indicates that you didn't handle the message at all - this is equivalent to passing a message through to DefWindowProc().

So I think the proper handling for your situation is, in your top-level window:

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

If your top-level window isn't in fact a dialog, you would do this:

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

这篇关于在WM_SETCURSOR处理程序中正确重置光标的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆