Graphics and Bitmap High CPU with VB.net

koossa
koossa used Ask the Experts™
on
I have a picturebox on my Windows form.  Form's windowstate = maximize
Picturebox Dock = fill

Here is my code .

Public Class Form1

  Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    Dim MyBmp As Bitmap
    If PictureBox1.Image Is Nothing Then
      MyBmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    Else
      MyBmp = New Bitmap(PictureBox1.Image)
    End If
    Dim MyGraphics As Graphics = Graphics.FromImage(MyBmp)
    MyGraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    MyGraphics.DrawEllipse(Pens.Blue, e.X - 50, e.Y - 50, 100, 100)
    MyGraphics.Dispose()
    PictureBox1.Image = MyBmp
  End Sub
End Class

Open in new window



When I draw circles on the form using the code above, the drawing gets very sticky and the CPU is rising.

What can I do to make it softer on the resources?

I know I can draw using Graphics.FromHwnd(picturebox1.handle), but when something moves over the form it wipes the drawing on that region.


Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®
Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Option #1
Public Class Form1

    Private Radius As Integer = 50
    Private GP As New System.Drawing.Drawing2D.GraphicsPath

    Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        Dim rc As New Rectangle(e.Location, New Size(1, 1))
        rc.Inflate(Radius, Radius)
        GP.AddEllipse(rc)
        PictureBox1.Refresh()
    End Sub

    Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
        e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
        e.Graphics.DrawPath(Pens.Blue, GP)
    End Sub

End Class

Open in new window

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Option #2:
Public Class Form1

    Private Radius As Integer = 50
    Private BMP As Bitmap = Nothing
    Private G As Graphics

    Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        If IsNothing(BMP) Then
            BMP = New Bitmap(PictureBox1.Width, PictureBox1.Height)
            G = Graphics.FromImage(BMP)
            PictureBox1.Image = BMP
        End If
        Dim rc As New Rectangle(e.Location, New Size(1, 1))
        rc.Inflate(Radius, Radius)
        G.DrawEllipse(Pens.Blue, rc)
        PictureBox1.Refresh()
    End Sub

End Class

Open in new window

Author

Commented:
Thank you for the 2 options.

They are both still a bit sticky.

Is n't there a way to draw it as fast as the following code ?

[code]
Public Class Form1

  Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    'Dim MyBmp As Bitmap
    'If PictureBox1.Image Is Nothing Then
    '  MyBmp = New Bitmap(PictureBox1.Width, PictureBox1.Height)
    'Else
    '  MyBmp = New Bitmap(PictureBox1.Image)
    'End If
    Dim MyGraphics As Graphics = Graphics.FromHwnd(PictureBox1.Handle)
    MyGraphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    MyGraphics.DrawEllipse(Pens.Blue, e.X - 50, e.Y - 50, 100, 100)
    MyGraphics.Dispose()
    'PictureBox1.Image = MyBmp
  End Sub
End Class
[/code]
Microsoft Azure 2017

Azure has a changed a lot since it was originally introduce by adding new services and features. Do you know everything you need to about Azure? This course will teach you about the Azure App Service, monitoring and application insights, DevOps, and Team Services.

Mike TomlinsonHigh School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009

Commented:
Will the circles only be drawn when the mouse button is down?

If so, then you can use CreateGraphics() to draw directly to the screen and only update the actual PictureBox with Refresh() when the mouse is let go:
Public Class Form1

    Private Radius As Integer = 50
    Private BMP As Bitmap = Nothing
    Private G As Graphics
    Private tmpG As Graphics

    Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
        If e.Button = Windows.Forms.MouseButtons.Left Then
            Cursor.Clip = PictureBox1.RectangleToScreen(PictureBox1.ClientRectangle)
            tmpG = PictureBox1.CreateGraphics
        End If
    End Sub

    Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        If e.Button = Windows.Forms.MouseButtons.Left Then
            If IsNothing(BMP) Then
                BMP = New Bitmap(PictureBox1.Width, PictureBox1.Height)
                G = Graphics.FromImage(BMP)
                PictureBox1.Image = BMP
            End If
            Dim rc As New Rectangle(e.Location, New Size(1, 1))
            rc.Inflate(Radius, Radius)
            G.DrawEllipse(Pens.Blue, rc)
            tmpG.DrawEllipse(Pens.Blue, rc)
        End If
    End Sub

    Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
        If e.Button = Windows.Forms.MouseButtons.Left Then
            tmpG.Dispose()
            Cursor.Clip = Nothing
            PictureBox1.Refresh()
        End If
    End Sub

End Class

Open in new window

Author

Commented:
Thank you very much for your replies
I don't understand the code, but it's supposed to draw when the mouse are moving (it's for children)

I have changed your code and it is working, but I don't know if it is correct, I have only removed the Picturebox1.refresh()

Public Class Form1

  Private Radius As Integer = 50
  Private BMP As Bitmap = Nothing
  Private G As Graphics
  Private tmpG As Graphics

  'Private Sub PictureBox1_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
  '  If e.Button = Windows.Forms.MouseButtons.Left Then
  '    Cursor.Clip = PictureBox1.RectangleToScreen(PictureBox1.ClientRectangle)
  '    tmpG = PictureBox1.CreateGraphics
  '  End If
  'End Sub

  Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
    'If e.Button = Windows.Forms.MouseButtons.Left Then
    tmpG = PictureBox1.CreateGraphics
    If IsNothing(BMP) Then
      BMP = New Bitmap(PictureBox1.Width, PictureBox1.Height)
      G = Graphics.FromImage(BMP)
      PictureBox1.Image = BMP
    End If
    Dim rc As New Rectangle(e.Location, New Size(1, 1))
    rc.Inflate(Radius, Radius)
    G.DrawEllipse(Pens.Blue, rc)
    tmpG.DrawEllipse(Pens.Blue, rc)
    tmpG.Dispose()
    Cursor.Clip = Nothing
    'PictureBox1.Refresh()

    'End If
  End Sub

  'Private Sub PictureBox1_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseUp
  '  If e.Button = Windows.Forms.MouseButtons.Left Then
  '    tmpG.Dispose()
  '    Cursor.Clip = Nothing
  '    PictureBox1.Refresh()
  '  End If
  'End Sub

End Class

Open in new window

High School Computer Science, Computer Applications, Digital Design, and Mathematics Teacher
Top Expert 2009
Commented:
My only concern would be the super fast repeated creation/disposal of the Graphics...

Use MouseEnter()/MouseLeave() so that you only create a Graphics when the mouse enters and then it is disposed of when the moues leaves:
Public Class Form1

    Private Radius As Integer = 50
    Private BMP As Bitmap = Nothing
    Private G As Graphics
    Private tmpG As Graphics = Nothing

    Private Sub PictureBox1_MouseEnter(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseEnter
        If IsNothing(tmpG) Then
            tmpG = PictureBox1.CreateGraphics
        End If
    End Sub

    Private Sub PictureBox1_MouseMove(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
        If IsNothing(BMP) Then
            BMP = New Bitmap(PictureBox1.Width, PictureBox1.Height)
            G = Graphics.FromImage(BMP)
            PictureBox1.Image = BMP
        End If

        Dim rc As New Rectangle(e.Location, New Size(1, 1))
        rc.Inflate(Radius, Radius)
        G.DrawEllipse(Pens.Blue, rc)
        If Not IsNothing(tmpG) Then
            tmpG.DrawEllipse(Pens.Blue, rc)
        End If
    End Sub

    Private Sub PictureBox1_MouseLeave(ByVal sender As Object, ByVal e As System.EventArgs) Handles PictureBox1.MouseLeave
        If Not IsNothing(tmpG) Then
            Dim rc As Rectangle = PictureBox1.RectangleToScreen(PictureBox1.ClientRectangle)
            If Not rc.Contains(Cursor.Position) Then
                tmpG.Dispose()
                tmpG = Nothing
            End If
        End If
    End Sub

End Class

Open in new window

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial