如果 Cursor 被锁定,则检测鼠标移动

Detect mouse movement if Cursor is locked

我正在开发 Cad 应用程序并希望实现捕捉 - 当用户将鼠标移近某个对象时,我将 Cursor.Position 设置为该对象的中心点。如果用户在任何方向上移动鼠标说 7 个像素,那么 Cursor 设置 free.The 我这样做的方式是 - 我存储捕捉的 Cursor 位置,然后在 MouseMoveEvent 下我计算从存储位置到当前位置的距离。如果这个位置小于定义的阈值,那么我将当前光标位置设置回存储值。每次调用 MouseMoveEvent 时,两个光标位置之间的微小差异都会添加到先前计算的差异中,因此迟早会达到我的阈值并且光标会跳出对齐位置。代码示例:

   var x = Cursor.Position.X - storedPosition.X;
   pixelsX += x;

   int threshold = 7;
   if (pixelsX > threshold)
   {
          Cursor.Position = new System.Drawing.Point(storedPosition.X + 10, storedPosition.Y);
          snapReleased = true;
   }

这个问题是,在每个 MouseMoveEvent 中,鼠标移动的量非常小,如果没有达到阈值,它会设置回存储位置,这会使光标闪烁(这很烦人)所以我的问题是 - 有没有一种在 Cursor 锁定在一个位置时检测鼠标移动的方法?

我不会"snap"鼠标指针。你知道鼠标卡住时的感觉吗?根据您的年龄,您可能还记得滚轮老鼠,它们里面有一个橡皮球。太可怕了。

相反,我认为您即将 select 或当前正在移动的物体应该会迅速做出反应。例如,当您要 select 一个对象时,当鼠标指针比阈值更近时,该对象将突出显示。用户可以点击鼠标并抓取对象。

移动物体时,当物体与另一个物体、引导线等的距离小于阈值时,该物体可以吸附到位

以下是一个自定义面板控件,它演示了一个捕捉到网格的所有者绘制的光标 (snapPoints)。系统光标在鼠标 entry/leave 上 hidden/shown。捕捉到点的距离由常量 snapLimit 控制。

using System;
using System.Collections.Generic;
using System.Windows.Forms;
using System.Drawing;

namespace WindowsFormsApplication1
    {

    public class DrawingSurface : Panel
        {
        private const double snapLimit = 7.0D;
        private List<Point> snapPoints = new List<Point>();
        private Point cursorPos;
        private Point lastDrawnPos;
        private bool drawCursor;

        public DrawingSurface() : base()
            {
            this.BorderStyle = BorderStyle.Fixed3D;
            this.BackColor = Color.AliceBlue;
            this.DoubleBuffered = true;
            this.Cursor = Cursors.Cross;
            }

        protected override void OnMouseEnter(EventArgs e)
            {
            base.OnMouseEnter(e);
            System.Windows.Forms.Cursor.Hide();
            }

        protected override void OnMouseLeave(EventArgs e)
            {
            base.OnMouseLeave(e);
            System.Windows.Forms.Cursor.Show();
            this.drawCursor = false;
            this.Invalidate();
            }

        protected override void OnPaint(PaintEventArgs e)
            {
            base.OnPaint(e);
            foreach (Point dot in this.snapPoints)
                {
                e.Graphics.FillEllipse(Brushes.Red, dot.X - 1, dot.Y - 1, 2, 2);
                }
            if (drawCursor)
                {
                Cursor cur = System.Windows.Forms.Cursor.Current;
                Point pt = this.cursorPos;
                pt.Offset(-cur.HotSpot.X, -cur.HotSpot.Y);
                Rectangle target = new Rectangle(pt, cur.Size);
                cur.Draw(e.Graphics, target);
                this.lastDrawnPos = this.cursorPos;
                }

            }

        protected override void OnMouseMove(MouseEventArgs e)
            {
            base.OnMouseMove(e);
            SetCursor(e.Location);
            }

        private void SetCursor(Point loc)
            {
            this.cursorPos = loc;
            foreach (Point pt in this.snapPoints)
                {
                double deltaX = loc.X - pt.X;
                double deltaY = loc.Y - pt.Y;
                double radius = Math.Sqrt((deltaX * deltaX) + (deltaY * deltaY));
                if (radius < snapLimit)
                    {
                    this.cursorPos = pt;
                    break;
                    }
                }
            if (lastDrawnPos != this.cursorPos)
                {
                this.drawCursor = true;
                this.Invalidate();
                }
            }

        protected override void OnSizeChanged(EventArgs e)
            {
            base.OnSizeChanged(e);
            this.snapPoints.Clear();
            for (int y = 0; y <= this.ClientRectangle.Height; y += 50)
                {
                for (int x = 0; x <= this.ClientRectangle.Width; x += 50)
                    {
                    this.snapPoints.Add(new Point(x, y));
                    }
                }
            }
        }
    }