【问题标题】:"Dynamic" mouse cursor in custom control in C# (WinForms)C#(WinForms)中自定义控件中的“动态”鼠标光标
【发布时间】: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 中实现这种“动态”光标的正确方法是什么?

  1. 我应该覆盖OnMouseMove

    protected override void OnMouseMove(MouseEventArgs e) {
        if(e.Y < ...) Cursor.Current = ...;
        else if(e.Y < ...) Cursor.Current = ...;
        else Cursor.Current = ...;
    
        base.OnMouseMove(e);
    }
    
  2. 或者我应该回退到覆盖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


【解决方案1】:

正确答案是:

在这种情况下只能使用WM_SETCURSOR(但不能使用OnMouseMove)

OnMouseMove 中使用Cursor.Current = ... 会导致光标持续闪烁。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-06-22
    • 2011-02-23
    • 1970-01-01
    • 1970-01-01
    • 2013-09-15
    • 1970-01-01
    • 2011-02-17
    相关资源
    最近更新 更多