none
Does BufferedGraphics work with anything other than a form? RRS feed

  • Question

  • Hi Everyone,

    I have been trying to use BufferedGraphics to speed up drawing on a picturebox or a panel. I cant get anything out of the picturebox and the panel wont stop blinking. I doublebuffered the panel and thats worse.

    Does BufferedGraphics work with anything other than a form?

    Imports System.ComponentModel
    
    Public Class Form1
        Private gBuffer As BufferedGraphics
    
        Private Sub Form1_Closing(sender As Object, e As CancelEventArgs) Handles Me.Closing
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
        End Sub
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Form1_Resize(0, Nothing)
            Timer1.Start()
        End Sub
    
        Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
    
            gBuffer = BufferedGraphicsManager.Current.Allocate(Panel1.CreateGraphics, Panel1.ClientRectangle)
            Panel1.Refresh()
    
        End Sub
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles Panel1.Paint
            If gBuffer IsNot Nothing Then
                gBuffer.Graphics.Clear(Color.Red)
                gBuffer.Graphics.FillRectangle(Brushes.White, 10, 10, 50, 50)
                gBuffer.Render()
            End If
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Panel1.Refresh()
        End Sub
    End Class
    

    Wednesday, May 10, 2017 10:07 PM

Answers

  • Well I discovered that if I call the paint events to draw by using invalidate or refresh and then call the render sub from the paint event I get the blinking. So instead I call the render sub directly from the timer and the resize events and now the blinking has stopped.

    So this example shows the graphicsbuffer working for the form, panel, or picturebox. So far...

    Public Class Form1
        Private gBuffer As BufferedGraphics
        Private thisControl As Integer = 3
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Panel1.Visible = False
            PictureBox1.Visible = False
            Select Case thisControl
                Case 2
                    Panel1.Visible = True
                Case 3
                    PictureBox1.Visible = True
            End Select
            Form1_Resize(0, Nothing)
    
            Timer1.Start()
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint,
                Panel1.Paint, PictureBox1.Paint
    
            Render(gBuffer.Graphics)
            gBuffer.Render()
        End Sub
    
        Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
    
            Select Case thisControl
                Case 1  'form
                    gBuffer = BufferedGraphicsManager.Current.Allocate(Me.CreateGraphics, Me.ClientRectangle)
                Case 2 'panel
                    gBuffer = BufferedGraphicsManager.Current.Allocate(Panel1.CreateGraphics, Panel1.ClientRectangle)
                Case 3 'picturebox
                    gBuffer = BufferedGraphicsManager.Current.Allocate(PictureBox1.CreateGraphics, PictureBox1.ClientRectangle)
            End Select
    
            Render(gBuffer.Graphics)
            gBuffer.Render()
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Render(gBuffer.Graphics)
            gBuffer.Render()
        End Sub
    
        Private Sub Render(g As Graphics)
            If g IsNot Nothing Then
                g.Clear(Color.Red)
                g.FillRectangle(Brushes.White, 10, 10, 50, 50)
    
            End If
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
    
        End Sub
    End Class
    

    • Marked as answer by tommytwotrain Thursday, May 11, 2017 12:45 PM
    Thursday, May 11, 2017 12:44 PM

All replies

  • Hi Tommy,

    If you DoubleBuffer the panel and draw onto with a bufferedGraphics you buffer a buffered graphics...

    If the painting itself (the code in the paint method) is fast enough, you can get relyable fast results with using a timer with a better precision, like with the CreateTimerQueueTimer api. Then I'd use the ordinary GraphicsObject and a doublebuffered panel. With a standard timer and an interval of 1 you'll get a panel update about every 12 Millisecs and no blinking:

    Public Class Form1
        Dim WithEvents panel1 As New DBPanel
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Form1_Resize(0, Nothing)
            panel1.Dock = DockStyle.Fill
            Me.Controls.Add(panel1)
            Timer1.Interval = 1
            Timer1.Start()
        End Sub
    
        Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            panel1.Refresh()
        End Sub
    
        Private Sub Panel1_Paint(sender As Object, e As PaintEventArgs) Handles panel1.Paint
            If Me.panel1 IsNot Nothing AndAlso Not Me.panel1.IsDisposed Then
                e.Graphics.Clear(Color.Red)
                e.Graphics.FillRectangle(Brushes.Blue, 10, 10, 50, 50)
            End If
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            panel1.Refresh()
        End Sub
    End Class
    
    Public Class DBPanel
        Inherits Panel
    
        Public Sub New()
            Me.DoubleBuffered = True
        End Sub
    End Class

    Regards,

      Thorsten

    Thursday, May 11, 2017 12:03 AM
  • Hi Thorsten,

    I see. Yes I understand.

    In this case I want to use the grahicsbuffer for the speed. It doubles or more the drawing speed. I just put the timer in to help make the example blink more.

    So its not the non blinking I am after, although that is a requirement. I want to use the graphicsbuffer for the speed. But I would also like to use it in a picturebox or panel sometimes for convenience. I use it on a form no problems but I cant get it to work right in a picturebox or control. Assuming that it is meant for that.

    Thursday, May 11, 2017 12:20 AM
  • Well I discovered that if I call the paint events to draw by using invalidate or refresh and then call the render sub from the paint event I get the blinking. So instead I call the render sub directly from the timer and the resize events and now the blinking has stopped.

    So this example shows the graphicsbuffer working for the form, panel, or picturebox. So far...

    Public Class Form1
        Private gBuffer As BufferedGraphics
        Private thisControl As Integer = 3
    
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            Panel1.Visible = False
            PictureBox1.Visible = False
            Select Case thisControl
                Case 2
                    Panel1.Visible = True
                Case 3
                    PictureBox1.Visible = True
            End Select
            Form1_Resize(0, Nothing)
    
            Timer1.Start()
        End Sub
    
        Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint,
                Panel1.Paint, PictureBox1.Paint
    
            Render(gBuffer.Graphics)
            gBuffer.Render()
        End Sub
    
        Private Sub Form1_Resize(sender As Object, e As EventArgs) Handles Me.Resize
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
    
            Select Case thisControl
                Case 1  'form
                    gBuffer = BufferedGraphicsManager.Current.Allocate(Me.CreateGraphics, Me.ClientRectangle)
                Case 2 'panel
                    gBuffer = BufferedGraphicsManager.Current.Allocate(Panel1.CreateGraphics, Panel1.ClientRectangle)
                Case 3 'picturebox
                    gBuffer = BufferedGraphicsManager.Current.Allocate(PictureBox1.CreateGraphics, PictureBox1.ClientRectangle)
            End Select
    
            Render(gBuffer.Graphics)
            gBuffer.Render()
    
        End Sub
    
        Private Sub Timer1_Tick(sender As Object, e As EventArgs) Handles Timer1.Tick
            Render(gBuffer.Graphics)
            gBuffer.Render()
        End Sub
    
        Private Sub Render(g As Graphics)
            If g IsNot Nothing Then
                g.Clear(Color.Red)
                g.FillRectangle(Brushes.White, 10, 10, 50, 50)
    
            End If
        End Sub
    
        Private Sub Form1_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
            If gBuffer IsNot Nothing Then gBuffer.Dispose()
    
        End Sub
    End Class
    

    • Marked as answer by tommytwotrain Thursday, May 11, 2017 12:45 PM
    Thursday, May 11, 2017 12:44 PM
  • PS Just more info for those interested. 

    Now that I have my larger project working with the graphicsbuffer drawing on the picturebox the render speed has tripled for this scene. I was animating this scene at 3 fps and now its 9 fps. There are 2000 50x50 pixel tiles drawn plus the vector animations and etc each timer tick.

    With more code optimizing I hope to do better. The next step for better speed would be to use a background bitmap buffer and only redraw the parts that have changed each timer tick. Right now I am redrawing the entire scene.

    Thursday, May 11, 2017 2:08 PM