Cattura alla griglia topo bloccarsi
-
21-08-2019 - |
Domanda
Sto lavorando su un programma che disegna una semplice griglia di punti. Vorrei che il mouse per scattare tra i punti sulla griglia di partenza, alla fine di disegnare linee sulla griglia.
Ho un metodo che prende nella posizione corrente del mouse (X, Y) e calcola la coordinata della griglia più vicino.
Quando creo un evento e si tenta di spostare il mouse per il nuovo coordinare l'intero sistema diventa a scatti. Il mouse non scatta senza problemi tra i punti della griglia.
Ho copiato un esempio di codice di seguito per illustrare ciò che sto cercando di fare. Qualcuno ha qualche consiglio che mi potrebbe offrire quanto a come posso eliminare il nervosismo all'interno del movimento del mouse?
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;
}
}
}
Soluzione
Credo di capire dove stai venendo. Hai semplicemente bisogno di essere qualche delta lontano dal punto di snap originale (il sinistro del mouse) prima di scattare al nuovo punto.
Ecco 50 righe di codice che illustrano quello che voglio dire: (Avviare un nuovo progetto VB.NET, aggiungere un nuovo modulo, copiare e incollare il codice, aggiungere un riferimento, del sistema, System.Drawing e 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
Altri suggerimenti
Non modificare la posizione del cursore. Non è necessario.
Invece, disegnare come se fosse scattato alla griglia. Quando l'utente fa clic da qualche parte, basta disegnare la linea dai punti della griglia più vicini.
Per esempio, se l'utente fa clic su (197.198), ma si sa che il punto più vicino è in realtà (200,200), basta tracciare una linea a (200,200) invece di (197.198).
E per favore, non si scherza con il reale posizione del cursore.
Non so se c'è un modo per nascondere il cursore del mouse. Se c'è, si può nascondere e disegnare voi stessi, senza modificare la posizione reale .
Il mouse mantiene scattare allo stesso punto, se si tenta di spostare - perché è ancora più vicino a quel punto ... Se si sposta il mouse a destra, spostare il cursore sul punto a sinistra di quello attuale, invece ricalcolare alla corrente. Applicare per gli altri 3 direzioni ...
Non vorrei raccomandare questo comportamento, però, causerà un sacco di irritazione. Snap i controlli alla rete, non il mouse.
Sono d'accordo con ruijoel, non si scherza con la posizione del cursore. E 'meglio avere una croce o un anello che viene disegnata in corrispondenza del punto gioco da ragazzi per mostrare all'utente che punto è quello che andranno a ruba ad un evento click.
Per far funzionare tutto questo ben si consiglia di guardare XOR-disegno in modo tale elemento viene cancellata non appena si passa a un nuovo punto di scatto.