【问题标题】:Having trouble drawing simple rectangle in picturebox在图片框中绘制简单矩形时遇到问题
【发布时间】:2014-09-15 18:44:31
【问题描述】:

我有一个将显示图像的图片框。我希望用户能够单击、拖动和鼠标移动到图像上的一个矩形。就像“我想用我在这张照片上画的这个矩形做点什么”。如果他们再次单击,我希望前一个矩形消失并且它们重新开始,或者当我单击一个按钮以清除他们绘制的突出显示矩形时。

所以我确实从 msdn 示例中找到了一些关于创建放大橡皮筋矩形的良好起始代码,我在下面进行了一些编辑,但我遇到了一些问题:

       Public bHaveMouse As Boolean
Public ptOriginal As Point
Public ptLast As Point
Public rect As Rectangle
Public b_Redraw As Boolean = False


' and Normalize the points and draw the reversible frame.
Private Sub MyDrawReversibleRectangle(ByVal p1 As Point, ByVal p2 As Point)
    Try
        'clear 

        ' Convert the points to screen coordinates.
        p1 = PointToScreen(p1)
        p2 = PointToScreen(p2)
        ' Normalize the rectangle.
        If (p1.X < p2.X) Then
            rect.X = p1.X
            rect.Width = p2.X - p1.X
        Else
            rect.X = p2.X
            rect.Width = p1.X - p2.X
        End If
        If (p1.Y < p2.Y) Then
            rect.Y = p1.Y
            rect.Height = p2.Y - p1.Y
        Else
            rect.Y = p2.Y
            rect.Height = p1.Y - p2.Y
        End If

        If rect.Width > pbZoneImage.Width Then
            rect.Width = pbZoneImage.Width
        End If

        If rect.Height > pbZoneImage.Height Then
            rect.Height = pbZoneImage.Height
        End If

        ' Draw the reversible frame.
        ControlPaint.DrawReversibleFrame(rect, Color.Red, FrameStyle.Thick)
    Catch ex As Exception

    End Try

End Sub

Private Sub pbZoneImage_MouseDown(sender As Object, e As MouseEventArgs) Handles pbZoneImage.MouseDown
    If e.Button <> Windows.Forms.MouseButtons.Left Then
        Exit Sub
    End If

    Try
        ' Make a note that we "have the mouse".
        bHaveMouse = True
        ' Store the "starting point" for this rubber-band rectangle.

        If b_Redraw Then
            If (ptLast.X <> -1) Then
                '     Dim ptCurrent As Point
                'ptCurrent.X = e.X
                'ptCurrent.Y = e.Y
                MyDrawReversibleRectangle(ptOriginal, ptLast)
            End If
            ' Set flags to know that there is no "previous" line to reverse.
            ptLast.X = -1
            ptLast.Y = -1
            ptOriginal.X = -1
            ptOriginal.Y = -1
        End If

        ptOriginal.X = e.X
        ptOriginal.Y = e.Y
        ' Special value lets us know that no previous
        ' rectangle needs to be erased.
        ptLast.X = -1
        ptLast.Y = -1
    Catch ex As Exception

    End Try

End Sub

Private Sub pbZoneImage_MouseMove(sender As Object, e As MouseEventArgs) Handles pbZoneImage.MouseMove
    Dim ptCurrent As Point
    ptCurrent.X = e.X
    ptCurrent.Y = e.Y
    ' If we "have the mouse", then we draw our lines.
    If (bHaveMouse) Then
        ' If we have drawn previously, draw again in
        ' that spot to remove the lines.
        If (ptLast.X <> -1) Then
            MyDrawReversibleRectangle(ptOriginal, ptLast)
        End If
        ' Update last point.
        ptLast = ptCurrent
        ' Draw new lines.
        MyDrawReversibleRectangle(ptOriginal, ptCurrent)
    End If
End Sub

Private Sub pbZoneImage_MouseUp(sender As Object, e As MouseEventArgs) Handles pbZoneImage.MouseUp

    'Try
    '    ' Set internal flag to know we no longer "have the mouse".
    bHaveMouse = False

End Sub

我的问题:有时在绘制它时不会删除之前绘制的矩形,或者如果我将鼠标悬停在某些按钮(如退出按钮)上,矩形就会消失!我希望他们留下来,以便我可以为其他程序记录矩形的起点和终点。当我点击清除矩形按钮时,我希望它们消失,但我觉得我对应该非常简单的事情感到困惑。

另一个问题是我试图防止矩形溢出图片框(Pbzoneimage)。但它确实如此,并且会改变颜色。

我哪里做错了?有没有更好的方法来完全绘制这个?

【问题讨论】:

  • 在paint事件中做所有的绘画...也就是说,要绘制的代码可以在你拥有的地方,但它需要从Paint事件中调用。您需要一个类或 Rectangle 变量来跟踪当前要绘制/绘制的图像
  • 那么,如果我必须使用paint 事件,我将如何将我的绘图功能移入其中?我应该从鼠标向上事件中调用它吗?还是悬停?
  • 您不必移动它,只需从那里调用它。请参阅this explanation 了解更多信息。听起来你大多只需要更新一个 Rectangle 变量并强制它现在重新绘制并使用picturebox.invalidate
  • 那么,除了在油漆中重绘它之外,这是否可以解决当我将鼠标悬停在退出按钮上时我的矩形消失的事实?

标签: vb.net winforms picturebox rectangles


【解决方案1】:

您需要两张位图,一张用于图片框 (img),一张用于清除它并绘制矩形 (imgClone)。

Private mouse_Down As Point
Private img As Bitmap
Private imgClone As Bitmap

Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    img = My.Resources..... 'or you can load the image from file

    PictureBox1.Image = img 'with this every time you invalidate it draws img to picturebox

    imgClone = CType(PictureBox1.Image.Clone, Bitmap)

End Sub

Private Sub PictureBox1_MouseDown(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
    mouse_Down = e.Location
End Sub

Private Sub PictureBox1_MouseMove(sender As System.Object, e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    If e.Button = MouseButtons.Left And e.Location <> mouse_Down Then
        DrawRectangle(e.Location)
    End If
End Sub

Private Sub DrawRectangle(ByVal pnt As Point)
    Dim g As Graphics

    g = Graphics.FromImage(img)

    g.DrawImage(imgClone, 0, 0) 'we are clearing img with imgClone. imgClone contains the original image without the rectangles

    If pnt.X = mouse_Down.X Or pnt.Y = mouse_Down.Y Then
        g.DrawLine(Pens.Firebrick, mouse_Down.X, mouse_Down.Y, pnt.X, pnt.Y)

    Else
        g.DrawRectangle(Pens.Firebrick, Math.Min(mouse_Down.X, pnt.X), Math.Min(mouse_Down.Y, pnt.Y),
                    Math.Abs(mouse_Down.X - pnt.X), Math.Abs(mouse_Down.Y - pnt.Y))

    End If

    g.Dispose()

    PictureBox1.Invalidate() 'draw img to picturebox
End Sub

如果需要清除图片框:

Dim g As Graphics

g = Graphics.FromImage(img)
g.DrawImage(imgClone, 0, 0)

g.Dispose()

PictureBox1.Invalidate()

变态

【讨论】:

  • 所以,我花了一段时间才完成这个,因为它太小了,你实际上看不到细红线。但主要是因为我认为它是基于鼠标点而不是相对图片框位置绘制的。否则,我认为这是一个有趣的解决方案。
  • @sparkysword 如果您想要更粗的线条,请使用自定义笔 Private myPen As Pen = New Pen(Color.Red, 3) 而不是 Pens.Red。我不明白 ...基于鼠标点而不是相对图片框位置
  • 所以我基本上必须将鼠标拖到我的第二台显示器上,以使红色方块与图片框一样大,大约只有 500x500。
  • @sparkysword 您的问题是在图片框中绘制简单的矩形。你想在画框上还是在屏幕上画画?
猜你喜欢
  • 2021-12-03
  • 1970-01-01
  • 2018-10-23
  • 1970-01-01
  • 1970-01-01
  • 2019-07-28
  • 1970-01-01
  • 2016-09-11
  • 1970-01-01
相关资源
最近更新 更多