如何在 C# 代码中获取 WM_NCHITTEST 消息的坐标?
我很想获得最快的方法,因为性能是一项要求。
3 回答
直到今天早上,我 100% 同意 Thomas Levesques 的回答,我从 msdn 中提取了相同的信息,并且代码(似乎)运行良好。但是,有一种情况会咬你,今天下午我花了三个小时才找到原因。
我的症状是,在我的一台开发机器上,在 VS2010 IDE 中,当我在某个 y 位置单击它时,我的控件只能通过单击来选择。表单顶部的非常小的控件根本无法通过单击来选择。不可点击区域的大小看起来与 Windows 窗体设计器周围的 IDE 大小相同,所以起初我以为我遇到了一些奇怪的鲜为人知的 DesignMode 问题。最令人困惑的一点是完全相同的项目(在不同的机器上签出 TFS)不会显示这种行为。
这是发生的事情:
假设您有一个双显示器设置,如此处所示(对于德语屏幕截图,我很抱歉,我手头没有英文操作系统):
如您所见,监视器 2 的左上角位于坐标 (1280, -256)。如果您使用上面显示的解决方案,如果鼠标确实位于 -30,您将得到类似 65505 的 y。这是因为位置存储为 LParam 的高位和低位WORD
。因此,这样做(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);
Casting toshort
为您提供正确的位置值。我也投了 x,因为你可以安排你的显示器,让第二台显示器在主显示器的左边,因此 x 位置也会有同样的问题。
我最近发现Point
为你工作的意愿的构造者之一。所以,简短的版本是:
Point pos = new Point(lParam.ToInt32());
来自 MSDN:
wParam
不使用该参数。lParam
低位字指定光标的 x 坐标。坐标相对于屏幕的左上角。
高位词指定光标的 y 坐标。坐标相对于屏幕的左上角。
所以你只需要从消息中提取低阶和高阶词lParam
:
int x = lParam.ToInt32() & 0x0000FFFF;
int y = (int)((lParam.ToInt32() & 0xFFFF0000) >> 16)
Point pos = new Point(x, y);
我不会太担心性能,因为这些操作只是位级算术......
请注意,这些坐标是相对于屏幕的。如果您想要相对于控件(或表单)的坐标,可以使用以下PointToClient
方法:
Point relativePos = theControl.PointToClient(pos);
我知道这个问题已经回答了,但除了......
Point p = new Point(m.LParam.ToInt32());
System.Drawing.Point 现在有一个专门设计用于接受这个精确值的构造函数。严格来说,我认为这可能是最简单的方法。
老实说,我不知道在发布其他答案时这个构造函数是否存在。
话虽如此,这可能不会更快,因为 takrl 的答案几乎肯定是上述构造函数在内部所做的。