【发布时间】:2017-02-27 08:25:26
【问题描述】:
我正在用 C# (Windows.Forms) 做一个(自定义绘制的)自定义控件。 鼠标光标形状应取决于我的自定义控件的哪一部分当前处于光标下。 (我称之为“动态光标”:我的意思是光标不仅取决于光标下的Control,还取决于鼠标坐标。)
在使用 WinAPI 时,我认为应该使用 WM_SETCURSOR 作为正确的方式:
//pseusocode
if(uMsg == WM_SETCURSOR) {
if((HWND)wParam == hwnd) {
POINT point;
GetCursorPos(&point);
ScreenToClient(hwnd, &point);
if(point.Y < ...) SetCursor(...);
else if(point.Y < ...) SetCursor(...);
else SetCursor(...);
return true;
}
else return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
所以,在 C# 中,我希望我会这样做:
protected override void OnNeedToSetCursor(NeedToSetCursorEventArgs e) {
if(...) Cursor.Current = ...;
else if(...) Cursor.Current = ...;
else Cursor.Current = ...;
}
但是,Control 中没有这样的事件或可覆盖的方法。
因此,问题是: 在 WinForms 中实现这种“动态”光标的正确方法是什么?
-
我应该覆盖
OnMouseMove:protected override void OnMouseMove(MouseEventArgs e) { if(e.Y < ...) Cursor.Current = ...; else if(e.Y < ...) Cursor.Current = ...; else Cursor.Current = ...; base.OnMouseMove(e); } -
或者我应该回退到覆盖
WndProc:protected override void WndProc(ref Message m) { if(m.Msg == 0x0020/*WM_SETCURSOR*/) { if(...) Cursor.Current = ...; else if(...) Cursor.Current = ...; else Cursor.Current = ...; m.Result = new IntPtr(-1); } else base.WndProc(ref m); }
附注:
请不要回答诸如“选择自己”或“我更喜欢这种方式”之类的问题。 因为这不是个人喜好问题,所以这是正确性问题。
如果两种方式都正确,请说“两种方式都正确”。如果只有一种方式是正确的,请解释为什么其他方式不正确。如果两种方法都“有效”,但其中一种有一些优点/缺点(例如:“鼠标移动方式具有更大的性能开销”,或“WM_MOUSEMOVE 消息不是专用于此,因此使用鼠标移动方式将设置光标形状为时已晚;即当鼠标移动 (125,19)->(125,20)->(125,21) 并且我在 (125,20) 中将光标形状设置为 NS_SIZE 时,它只会在 (125,21) 中更改)"),请告诉我。
P.P.S.:我对这个网站很失望。哪个白痴会认为这个问题是基于意见的?他读过“P.S.”吗?他读对了吗?
【问题讨论】:
-
是的。您需要自己选择一个。
-
@HansPassant,请看附言
-
使用mousemove 的一个很好的理由是,x 和y 相对于控件的相对位置的定位已经为您完成了。使用消息时,您必须先执行 PointToClient(Cursor.Position)。并不完全令人震惊,但鼠标移动是为了我们的方便。
-
@Me.Name,是的,我明白这一点。但是,WM_SETCURSOR 的消息是什么?如果 WM_MOUSEMOVE (OnMouseMove) 就足够了,微软为什么要创建 WM_SETCURSOR 事件?在 WM_MOUSEMOVE (OnMouseMove) 中设置光标是否有一些缺点/副作用?
-
好吧,那么我还想补充一点,据我所知(虽然没有证据),mousemove 的工作已经完成,无论该方法是否被覆盖。如果确实如此,那么严格的性能方面,重做 wndproc 中的检查和游标转换最终会产生更大的性能开销。
标签: c# winforms cursor custom-controls