Search code examples
vb.netwinformsgraphicsmouseeventpicturebox

Draw Rectangle over PictureBox


The next code lets you draw Rectangles in the Form with mouse clics. Why not, or how can be draw over a PictureBox?

Public Class Form1
Dim SelectRect As Rectangle = New Rectangle()
Dim ps As Point = New Point()
Dim pe As Point = New Point()

This catch the first click, starting point or corner of the rectangle

Private Sub Form1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseDown
    SelectRect.Width = 0
    SelectRect.Height = 0
    SelectRect.X = e.X
    SelectRect.Y = e.Y
    ps.X = e.X
    ps.Y = e.Y
    pe = ps
End Sub

This part determine the width and height of the rectangle:

Private Sub Form1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseMove
    If (e.Button = MouseButtons.Left) Then
        ControlPaint.DrawReversibleFrame(Me.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed)
        SelectRect.Width = e.X - SelectRect.X
        SelectRect.Height = e.Y - SelectRect.Y
        ControlPaint.DrawReversibleFrame(Me.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed)
    End If

End Sub

This part determine the last coordinate, the second corner of the rectangle:

Private Sub Form1_MouseUp(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles MyBase.MouseUp
    Dim g As Graphics = Me.CreateGraphics()
    Dim p As Pen = New Pen(Color.Blue, 2)
    ControlPaint.DrawReversibleFrame(Me.RectangleToScreen(SelectRect), Color.Black, FrameStyle.Dashed)
    g.DrawRectangle(p, SelectRect)
    g.Dispose()
End Sub
   End Class

Solution

  • Your code uses a control (a Form in this case) mouse events to enable the drawing of rectangular shapes, with the help of guidelines, provided by Control.DrawReversibleFrame().
    You just have to define the same events of a different, drawable, control - like a PictureBox - and repeat, more or less, the same procedure (after a cleanup).

    As many have stated, here and before, use the Graphics object that the Paint event kindly offers, so that your drawing will persist.
    The Graphics object you get from Control.CreateGraphics() is not persistent, and it can be erase/clipped when you don't want to.
    Use it only if that is really what you have planned to do for the reasons you know.


    I've adden an event handler that checks if Control Key is pressed.
    If Control is pressed, you add a rectangle, if not, only one rectangle is drawn.
    I've also included, as an example, a line of code that fills the rectangle. I think it's interesting, because you have to control the size of the invalidated Region.
    Comment out these lines of code to draw just the frame:

    SelectRect.Inflate(CInt(-_pen.Width / 2), CInt(-_pen.Width / 2))
    e.Graphics.FillRectangle(_brush, SelectRect)
    


    enter image description here

    Dim SelectRect As Rectangle = New Rectangle()
    Dim _pen As Pen = New Pen(Color.Green, 4)
    Dim _brush As SolidBrush = New SolidBrush(Color.Orange)
    Dim _ControlPressed As Boolean = False
    
    Private Sub Form1_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
        _ControlPressed = (e.Modifiers And Keys.Control) = Keys.Control
    End Sub
    
    Private Sub Form1_KeyUp(sender As Object, e As KeyEventArgs) Handles Me.KeyUp
        _ControlPressed = (e.Modifiers And Keys.Control) = Keys.Control
    End Sub
    
    
    Private Sub PictureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseDown
        SelectRect.Location = e.Location
        SelectRect.Size = New Size(0, 0)
    End Sub
    
    Private Sub PictureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseMove
        If (e.Button = MouseButtons.Left) Then
            ControlPaint.DrawReversibleFrame(PictureBox1.RectangleToScreen(SelectRect), PictureBox1.BackColor, FrameStyle.Dashed)
            SelectRect.Width = e.X - SelectRect.X
            SelectRect.Height = e.Y - SelectRect.Y
            ControlPaint.DrawReversibleFrame(PictureBox1.RectangleToScreen(SelectRect), PictureBox1.BackColor, FrameStyle.Dashed)
        End If
    End Sub
    
    Private Sub PictureBox1_MouseUp(sender As Object, e As MouseEventArgs) Handles PictureBox1.MouseUp
    
        If (e.Y < SelectRect.Y) Then
            SelectRect.Location = If(SelectRect.Location.X > e.X,
                                     New Point(e.X, e.Y), New Point(SelectRect.X, e.Y))
            SelectRect.Size = New Size(Math.Abs(SelectRect.Width), Math.Abs(SelectRect.Height))
        Else
            If SelectRect.Location.X > SelectRect.Right Then
                SelectRect.Location = New Point(e.X, SelectRect.Y)
                SelectRect.Size = New Size(Math.Abs(SelectRect.Width), Math.Abs(SelectRect.Height))
            End If
        End If
    
        If _ControlPressed Then
            Dim _InflatedRect As Rectangle = New Rectangle(SelectRect.Location, SelectRect.Size)
            _InflatedRect.Inflate(CInt(_pen.Width / 2), CInt(_pen.Width / 2))
            PictureBox1.Invalidate(_InflatedRect)
        Else
            PictureBox1.Invalidate()
        End If
    
    End Sub
    
    Private Sub PictureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PictureBox1.Paint
        'Draw the outer rectangle with the color of _pen
        e.Graphics.DrawRectangle(_pen, SelectRect)
    
        'Fill the rectangle with the color of _brush
        'It's half Pen.Width smaller so it doesn't erase the contour
        SelectRect.Inflate(CInt(-_pen.Width / 2), CInt(-_pen.Width / 2))
        e.Graphics.FillRectangle(_brush, SelectRect)
    
    End Sub