获取WM_NCHITTEST消息的坐标?

Ver*_*cas 7 c# wndproc winforms

如何在C#代码中获取WM_NCHITTEST消息的坐标?
我很想获得最快的方式,因为性能是必需的.

tak*_*krl 13

直到今天早上,我已经100%同意Thomas Levesques的回答,我从msdn中提取了相同的信息并且代码(貌似)工作得很好.但是,有一种情况会让你感到困惑,我今天下午花了三个小时才找到原因.

我的症状是,在我的一台开发机器上,在VS2010 IDE中,我的控件只能通过点击我在某个y位置点击它来选择.窗体顶部的非常小的控件无法通过单击进行选择.不可点击的区域大小看起来与Windows窗体设计器周围的IDE大小相同,所以起初我以为我有一些奇怪的鲜为人知的DesignMode问题.最令人困惑的是,完全相同的项目(在不同的机器上检出TFS)不会显示此行为.

这是发生的事情:

考虑你有一个双显示器设置如此处所示(抱歉德国截图,我手头没有英文操作系统):

双显示器设置

如您所见,监视器2的左上角位于坐标(1280,-256)处.如果您使用上面显示的解决方案,如果鼠标确实在-30,您将获得65505之类的y.这是因为位置存储为WORDLParam的高低顺序.因此,do (lParam.ToInt32() & 0xFFFF0000) >> 16会为您提供y位置的正确位.但是,将此转换为int会产生65505,因为您正在转换为错误的数据类型.

解:

int x = (short)(lParam.ToInt32() & 0x0000FFFF);
int y = (short)((lParam.ToInt32() & 0xFFFF0000) >> 16);
Point pos = new Point(x, y);
Run Code Online (Sandbox Code Playgroud)

施法可short为您提供正确的位置值.我也投了x,因为你可以安排你的显示器,第二个显示器留在主显示器,因此x位置会有同样的问题.

我最近发现Point了为你工作的意志的构造者之一.所以,简短的版本是:

Point pos = new Point(lParam.ToInt32());
Run Code Online (Sandbox Code Playgroud)


Tho*_*que 11

来自MSDN:

wParam
不使用此参数.

lParam
低位字指定光标的x坐标.坐标相对于屏幕的左上角.
高位字指定光标的y坐标.坐标相对于屏幕的左上角.

所以你只需要从消息中提取低阶和高阶词lParam:

int x = lParam.ToInt32() & 0x0000FFFF;
int y = (int)((lParam.ToInt32() & 0xFFFF0000) >> 16)
Point pos = new Point(x, y);
Run Code Online (Sandbox Code Playgroud)

我不会太担心性能,因为这些操作只是位级算术...

请注意,这些坐标是相对于屏幕的.如果需要相对于控件(或表单)的坐标,可以使用以下PointToClient方法:

Point relativePos = theControl.PointToClient(pos);
Run Code Online (Sandbox Code Playgroud)

  • 考虑一下下一个答案.TL; DR,在将它们分配给支持多显示器设置(具有负坐标)之前,将"x"和"y"转换为"(短)". (2认同)

Jos*_*ech 8

我知道这个问题已经回答了,但除了...

Point p = new Point(m.LParam.ToInt32());
Run Code Online (Sandbox Code Playgroud)

System.Drawing.Point现在有一个专门设计用于接受这个精确值的构造函数.严格来说,我认为这可能是最简单的方法.

说实话,我不知道当其他答案发布时,这个构造函数是否存在.

总而言之,这可能不会更快,因为takrl的答案几乎肯定是前面提到的构造函数在内部做的事情.