0

我正在尝试在我的应用程序中实现一项功能,以将光标捕捉到场景中的网格边缘。就目前而言,我确实有框架来获取当前MouseMove提供的e.Location并转换为我的世界坐标并返回屏幕 - 并且值匹配。请参阅下面的基本代码概述。

public void Scene_MouseMove(object sender, MouseEventArgs e)
{
    Vector2 world = ScreenToWorld(e.Location);

    ---> Check here to make sure the world coordinates returned
         fall inside my grid scene edges.
    if (world.X < Grid.Left) world.x = Grid.Left;

    Point target = WorldToScreen(world);

    // set cursr desired position
    Cursor.Position = (sender as PictureBox).PointToScreen( target );
}

我遇到的问题是 MouseMove 在鼠标移动之后被调用,所以当我点击网格的边缘时,我看到鼠标过冲了一帧,然后自行纠正。当我移动鼠标时,这会导致光标在边缘抖动。我想这样做,所以当我击中边缘时,光标停止在其轨道上,但我不知道如何在鼠标移动之前捕获数据!

也许我正在解决这个错误,所以任何建议将不胜感激。

仅供参考 - 这是我尝试实现的 SnapToGrid 功能的第一部分。

编辑:一个更简单的例子:

您可以在下面运行简单示例时看到我的问题。请注意光标在您移动时如何在每一帧中闪烁?

bool g_Set = false;
public void Scene_MouseMove(object sender, MouseEventArgs e)
{
    // stop MouseMove from flooding the control recursively
    if(g_Set) { g_Set = false; return; }
    g_Set = true;
    Cursor.Position = new Point(400,400);
}

C# 是否支持 API 中的任何内容以在实际移动 Cursor 之前捕获MouseMove,还是我应该只是研究实现我自己的 Cursor 类来隐藏Form.Cursor并只渲染我的(我需要研究的其他内容)也不知道该功能)。

4

4 回答 4

0

要捕捉到边缘,请为捕捉留出一点空间,例如 2 个像素:

if (world.X - 2 < Grid.Left) world.x = Grid.Left;

将光标限制在控件的矩形内,例如:aButton

Cursor.Clip = aButton.RectangleToScreen(aButton.ClientRectangle);

释放光标:

Cursor.Clip = null;
于 2013-03-07T03:35:43.250 回答
0

使用线性外推计算进入帧之前的最后一个像素。您需要两个点 P1 和 P2。进入前的点 P0 可以近似为

P0.X = P2.X - P1.X
P0.Y = P2.Y - P1.Y
于 2013-03-07T04:11:23.053 回答
0

你可以创建一个UserControl上面有一个场景的。将场景放在中心,周围有一个已知大小的边距。UserControl.BackColor = Transparent。_ 处理事件

private void UserControl_MouseMove(Object sender,MouseEventArgs e)
{
    // check if mouse is entering the Scene, you know the size of the margin
}

从那里你可以想出逻辑来预测鼠标进入场景。

于 2013-03-07T14:59:46.360 回答
0

因此,在研究了这一天之后,我最终崩溃了,写了一个 Cursor 类。这里重要的是我正在使用 Managed DirectX 在 PictureBox 中进行渲染,所以我有一条出路。

实际上,我在System.Cursor进入控件时隐藏了它,并通过在每帧之间获取 System.Cursor 的偏移量、应用我的逻辑并确定我想要渲染“我的”光标的位置来开始渲染我自己的光标。请参阅下面我如何处理偏移量:

public bool g_RecalcCursor = false;
public Point g_Reference = new Point(400,400);
public void SceneView_MouseMove(object sender, MouseEventArgs e)
{
    // this logic avoids recursive calls into MouseMove
    if (g_RecalcCursor)
    { 
        g_RecalcCursor = false;
        return;
    }

    Point ee = (sender as PictureBox).PointToScreen(e.Location);
    Point delta = new Point(g_Reference.X - ee.X, g_Reference.Y - ee.Y);

    //------------------------------------------//
    // I can use delta now to move my cursor    //
    // and apply logic "BEFORE" it renders      //
    //------------------------------------------//

    g_RecalcCursor = true;
    Cursor.Position = g_Reference;
}

我很惊讶在鼠标移动(MouseMoving / MouseMove )时没有像Form_Closing / Form_Closed这样的调用- 但话又说回来,System.Cursor可能不应该被应用程序操纵,以免恶化用户对它应该如何正常工作的体验,因此限制了 API 中的操作功能。

我仍然愿意接受任何可以让我使用 System.Cursor 的建议......

于 2013-03-07T19:43:31.833 回答