Search code examples
vb.netwinformsgraphicspaintflicker

How to stop flickering when redrawing ellipses in windows forms


Im trying to make a ball bouncing around on the screen, which is mostly working apart from an annoying flicker everytime it moves.

Ive been searching for a while, and most sites tell you to enable double buffering, which slightly helps but it still flickers badly.

Does anyone have any advice on how to fix this?

Thanks :)

My Code:

Imports System.Drawing
Public Class Form1

    Public gr As Graphics
    Public XSpeed As Integer = 2
    Public YSpeed As Integer = 2
    Public ParticleCoord(1) As Integer
    Public Blackbrush As New SolidBrush(Color.Black)



    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        gr = Me.CreateGraphics()

        YSpeed = CInt(Math.Ceiling(Rnd() * 10))
        XSpeed = CInt(Math.Ceiling(Rnd() * 10))

        ParticleCoord = {50, 50}

        Timer.Enabled = True

    End Sub

    Private Sub ParticleMove(ByRef XSpeed, ByRef YSpeed)
        If (ParticleCoord(0) < (12 + 1189) And ParticleCoord(0) > 12) And (ParticleCoord(1) < (12 + 449) And ParticleCoord(1) > 12) Then
            ParticleCoord = {ParticleCoord(0) + XSpeed, ParticleCoord(1) + YSpeed}
            gr.Clear(Color.White)
            gr.FillEllipse(Blackbrush, (ParticleCoord(0) + XSpeed), (ParticleCoord(1) + YSpeed), 50, 50)
        ElseIf (ParticleCoord(0) < (12 + 1189) And ParticleCoord(0) > 12) Then
            YSpeed = -YSpeed
            ParticleCoord = {ParticleCoord(0) + XSpeed, ParticleCoord(1) + YSpeed}
            gr.Clear(Color.White)
            gr.FillEllipse(Blackbrush, (ParticleCoord(0) + XSpeed), (ParticleCoord(1) + YSpeed), 50, 50)
        ElseIf (ParticleCoord(1) < (12 + 449) And ParticleCoord(1) > 12) Then
            XSpeed = -XSpeed
            ParticleCoord = {ParticleCoord(0) + XSpeed, ParticleCoord(1) + YSpeed}
            gr.Clear(Color.White)
            gr.FillEllipse(Blackbrush, (ParticleCoord(0) + XSpeed), (ParticleCoord(1) + YSpeed), 50, 50)
        Else
            YSpeed = -YSpeed
            XSpeed = -XSpeed
            ParticleCoord = {ParticleCoord(0) + XSpeed, ParticleCoord(1) + YSpeed}
        End If
    End Sub

    Private Sub Timer_Tick(sender As Object, e As EventArgs) Handles Timer.Tick
        ParticleMove(XSpeed, YSpeed)
    End Sub


End Class

Solution

  • As stated out in the comments, you should always use the Graphics object from the Paint-event. To invoke a redraw, call Invalidate() on your control. Do not use Refresh() (not that bad) or Application.DoEvents() (very bad) to perform redraws.

    Bonus: Pro-Tip for a very smooth drawing experience

    Get rid of OnPaintBackground(), see my other answer here.

    With this, you'll get good rendering performance (for GDI+), I use this a lot. You can see it over here in a fun project I made to analyse WinForms control hierarchies: WinFormsCT on GitHub.

    WinFormsCT