Привязка к сетке мыши блокировка
Я работаю над приложением, которое рисует простую точечную сетку. Я бы хотел, чтобы мышь щелкала между точками на сетке, в конечном итоге рисуя линии на сетке.
У меня есть метод, который принимает текущее местоположение мыши (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, чтобы элемент удалялся при переходе к новой точке привязки.