Привязка к сетке мыши блокировка

Я работаю над приложением, которое рисует простую точечную сетку. Я бы хотел, чтобы мышь щелкала между точками на сетке, в конечном итоге рисуя линии на сетке.

У меня есть метод, который принимает текущее местоположение мыши (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;
        }
    }
}

4 ответа

Решение

Я думаю, я понимаю, откуда ты. Вам просто нужно быть на некотором расстоянии от исходной точки привязки (щелчок левой кнопкой мыши), прежде чем привязываться к новой точке.

Вот 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

Не изменяйте положение курсора. Вам не нужно.

Вместо этого нарисуйте, как будто он был привязан к сетке. Когда пользователь щелкает где-то, просто нарисуйте линию от ближайших точек сетки.

Например, если пользователь нажимает на (197,198), но вы знаете, что ближайшая точка на самом деле (200,200), просто нарисуйте линию (200,200) вместо (197,198).

И, пожалуйста, не связывайтесь с фактическим положением курсора.


Я не знаю, есть ли способ скрыть курсор мыши. Если есть, вы можете спрятать его и нарисовать самостоятельно, не изменяя реальную позицию.

Ваша мышь продолжает привязываться к той же точке, если вы пытаетесь переместить ее - потому что она все еще ближе к этой точке... Если вы перемещаете мышь влево, переместите курсор в точку слева от текущей вместо пересчета в электрический ток. Подать заявку на 3 других направления...

Я не рекомендовал бы такое поведение, хотя, это вызовет много раздражения. Привязывайте свои элементы управления к сетке, а не к мышке.

Я согласен с ruijoel, не связывайтесь с позицией курсора. Лучше иметь крест или кольцо, нарисованное в точке привязки, чтобы показать пользователю, к какой точке будет привязана точка щелчка.

Чтобы это работало хорошо, вы можете захотеть взглянуть на xor-Drawing, чтобы элемент удалялся при переходе к новой точке привязки.

Другие вопросы по тегам