Привязка к сетке мыши блокировка - PullRequest
2 голосов
/ 11 декабря 2008

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

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

6 голосов
/ 11 декабря 2008

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

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

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

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


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

3 голосов
/ 11 декабря 2008

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

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

2 голосов
/ 11 декабря 2008

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

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

0 голосов
/ 11 декабря 2008

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

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...