画线精度?

DrawLine Accuracy?

我试图重新创建一个我很久以前尝试过的小东西。它实际上只是一个简单的绘画程序。代码基本上是:

    Public Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
    X = Control.MousePosition.X
    Y = Control.MousePosition.Y
    Mdown = True
End Sub

Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
    Dim g As Graphics = Me.CreateGraphics
    Dim NX As Integer = Control.MousePosition.X
    Dim NY As Integer = Control.MousePosition.Y
    If Mdown = True Then
        g.DrawLine(System.Drawing.Pens.Red, X, Y, NX, NY)
        X = NX
        Y = NY
    End If

End Sub

Private Sub Form1_MouseUp(sender As Object, e As MouseEventArgs) Handles Me.MouseUp
    Mdown = False
End Sub

效果很好,随着鼠标的移动,线条从主要点绘制到下一个点。但是,绘制线的准确性值得怀疑。在我的第二台显示器(运行 1280x720)上绘制常规 window 尺寸 (586, 634) 时,线条非常接近鼠标尖端(但不准确)。但是当 window 出现在我的主屏幕 (1920x1080) 上时,线路就断了。这是否有特定原因,因为我认为调用 Control.MousePosition.X/Y 得到了鼠标相对于 window 大小而不是屏幕大小的位置? (或其他)

我通常能够自己解决这些问题,但总的来说这似乎是错误的。有什么想法吗?

来自 MSDN:

The MousePosition property returns a Point that represents the mouse cursor position at the time the property was referenced. The coordinates indicate the position on the screen, not relative to the control, and are returned regardless of whether the cursor is positioned over the control. The coordinates of the upper-left corner of the screen are 0,0.

https://msdn.microsoft.com/en-us/library/system.windows.forms.control.mouseposition%28v=vs.110%29.aspx

您正在获取鼠标相对于屏幕的位置,而不是相对于引发鼠标事件的控件的位置。

对于后者,您应该使用 MouseEventArgs 变量 e,特别是它的 Location 属性.

这样你就可以获得相对于表单而不是屏幕的位置。

例如

Public Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
    X = e.X 'Equal to X = e.Location.X
    Y = e.Y 'Equal to Y = e.Location.Y
    Mdown = True
End Sub

所以这不是画线不准确的问题,而是提供给DrawLine方法的坐标的问题。在您的代码中,您可以注意到偏移量随窗体在屏幕上的位置而变化。

当您使用 CreateGraphics() 绘图时,绘图是 临时的 (minimize/restore 应用程序,看看会发生什么)。要使绘图 持久化 ,请将信息存储在 GraphicsPath 中,并在通过 e.GraphicsPaint( ) 表单事件:

Public Class Form1

    Private pt1 As Point
    Private curGP As Drawing2D.GraphicsPath
    Private GPs As New List(Of Drawing2D.GraphicsPath)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles Me.Load
        Me.DoubleBuffered = True
    End Sub

    Public Sub Form1_MouseDown(sender As Object, e As MouseEventArgs) Handles Me.MouseDown
        If e.Button = MouseButtons.Left Then
            curGP = New Drawing2D.GraphicsPath
            GPs.Add(curGP)
            pt1 = New Point(e.X, e.Y)
        End If
    End Sub

    Private Sub Form1_MouseMove(sender As Object, e As MouseEventArgs) Handles Me.MouseMove
        If e.Button = MouseButtons.Left Then
            Dim pt2 As New Point(e.X, e.Y)
            curGP.AddLine(pt1, pt2)
            pt1 = pt2
            Me.Invalidate()
        End If
    End Sub

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        For Each GP As Drawing2D.GraphicsPath In GPs
            e.Graphics.DrawPath(Pens.Red, GP)
        Next
    End Sub

End Class