【问题标题】:Snap to grid mouse locking up对齐网格鼠标锁定
【发布时间】:2008-12-11 12:50:04
【问题描述】:

我正在开发一个绘制简单点网格的应用程序。我希望鼠标在网格上的点之间捕捉,最终在网格上画线。

我有一个方法可以获取当前鼠标位置 (X,Y) 并计算最近的网格坐标。

当我创建一个事件并尝试将鼠标移动到新坐标时,整个系统变得不稳定。鼠标在网格点之间不平滑。

我复制了下面的代码示例来说明我正在尝试做的事情。关于如何消除鼠标移动中的跳动,有没有人可以向我提供任何建议?


using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;

namespace GridTest
{
    public partial class Form1 : Form
    {
        Graphics g;
        const int gridsize = 20;

        public Form1()
        {
            InitializeComponent();
            g = splitContainer1.Panel2.CreateGraphics();
            splitContainer1.Panel2.Invalidate();
        }

        private void splitContainer1_Panel2_Paint(object sender, PaintEventArgs e)
        {
            Drawgrid();
        }

        private void Drawgrid()
        {
            for (int x = 0; x < splitContainer1.Panel2.ClientSize.Width; x += gridsize)
            {
                for (int y = 0; y < splitContainer1.Panel2.ClientSize.Height; y += gridsize)
                { g.DrawLine(Pens.Black, new Point(x, y), new Point(x + 1, y)); }
            }
        }

        private void splitContainer1_Panel2_MouseMove(object sender, MouseEventArgs e)
        {
            Point newPosition = new Point();
            newPosition = RoundToNearest(gridsize, e.Location);
            Cursor.Position = splitContainer1.Panel2.PointToScreen(newPosition);
        }

        private Point RoundToNearest(int nearestRoundValue, Point currentPoint)
        {
            Point newPoint = new Point();
            int lastDigit;

            lastDigit = currentPoint.X % nearestRoundValue;

            if (lastDigit >= (nearestRoundValue/2))
            { newPoint.X = currentPoint.X - lastDigit + nearestRoundValue; }
            else
            { newPoint.X = currentPoint.X - lastDigit; }

            lastDigit = currentPoint.Y % nearestRoundValue;
            if (lastDigit >= (nearestRoundValue / 2))
            { newPoint.Y = currentPoint.Y - lastDigit + nearestRoundValue; }
            else
            { newPoint.Y = currentPoint.Y - lastDigit; }

            return newPoint;
        }
    }
}

【问题讨论】:

    标签: c# grid mouse cursor-position onmousemove


    【解决方案1】:

    不要修改光标位置。你不需要。

    取而代之的是,绘制就好像它被捕捉到了网格。当用户点击某处时,只需从最近的网格点画线。

    例如,如果用户点击 (197,198),但您知道最近的点实际上是 (200,200),那么只需画一条线到 (200,200) 而不是 (197,198)。

    请不要弄乱实际光标位置。


    我不知道是否有某种方法可以隐藏鼠标光标。如果有,您可以隐藏它并自己绘制它,无需修改实际位置

    【讨论】:

      【解决方案2】:

      如果您尝试移动鼠标,它会一直捕捉到同一点 - 因为它仍然最接近该点...如果您将鼠标向左移动,请将光标移动到当前鼠标左侧的点在当前重新计算。申请其他3个方向...

      但我不推荐这种行为,它会引起很多恼怒。将控件对齐到网格,而不是鼠标。

      【讨论】:

        【解决方案3】:

        我想我明白你来自哪里。在捕捉到新点之前,您只需与原始捕捉点(鼠标左键单击)相距一些增量。

        这里有 50 行代码说明了我的意思: (启动一个新的 VB.NET 项目,添加一个新模块,复制并粘贴代码,添加对 System、System.drawing 和 System.Windows.Forms 的引用)

        Imports System Imports System.Drawing Imports System.Windows.Forms Module modSnap Public Const strApplicationTitle As String = "Snap Demo" Public frmSnap As SnapForm Public ptSnap, ptStart, ptEnd As Point Public Class SnapForm Inherits Form Public Sub New() Me.Text = "Snap Demo" Me.ClientSize = New Size(800, 600) Me.FormBorderStyle = Windows.Forms.FormBorderStyle.FixedSingle Me.MaximizeBox = False Me.StartPosition = FormStartPosition.CenterScreen Me.DoubleBuffered = True End Sub Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs) MyBase.OnPaint(e) e.Graphics.Clear(Color.Black) For row As Integer = 20 To 780 Step 20 For col As Integer = 20 To 580 Step 20 e.Graphics.DrawEllipse(Pens.Blue, New Rectangle(row - 2, col - 2, 4, 4)) Next Next e.Graphics.DrawLine(Pens.Red, ptStart, ptEnd) End Sub Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs) MyBase.OnMouseDown(e) Dim x As Integer = CInt(e.X / 20) * 20 Dim y As Integer = CInt(e.Y / 20) * 20 ptStart = New Point(x, y) ptSnap = New Point(x, y) Windows.Forms.Cursor.Position = Me.PointToScreen(ptSnap) End Sub Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs) MyBase.OnMouseMove(e) If e.Button = Windows.Forms.MouseButtons.Left Then Dim x As Integer = CInt(e.X / 20) * 20 Dim y As Integer = CInt(e.Y / 20) * 20 ' must be some delta away from original snap point If (x < ptSnap.X - 15 Or x > ptSnap.X + 15) Or (y < ptSnap.Y - 15 Or y > ptSnap.Y + 15) Then ptSnap = New Point(x, y) ptEnd = New Point(x, y) Me.Invalidate(False) Windows.Forms.Cursor.Position = Me.PointToScreen(ptSnap) End If End If End Sub End Class Public Sub main() Try frmSnap = New SnapForm Application.Run(frmSnap) Catch ex As Exception MessageBox.Show(ex.Message, strApplicationTitle, MessageBoxButtons.OK, MessageBoxIcon.Error) Finally frmSnap.Dispose() End Try End Sub End Module

        【讨论】:

          【解决方案4】:

          我同意ruijoel,不要乱用光标位置。 最好在捕捉点处绘制一个十字或一个环,以向用户显示在点击事件中将捕捉到的点。

          为了使其正常工作,您可能需要查看 xor-drawing 以便在您移动到新的捕捉点后删除该项目。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2016-05-26
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            相关资源
            最近更新 更多