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

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

У меня есть метод, который принимает текущее местоположение мыши (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;
        }
    }
}
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
2
0
4 831
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

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

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

Не меняйте положение курсора. Тебе это не нужно.

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

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

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


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

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

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

Ответ принят как подходящий

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

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

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