locked
Problem with flickering screen when drawing on form RRS feed

  • Question

  • Hi,
    I have a problem with flickering on screen when it´s redrawn. I use Forms and I draw vector-grapichs thru GraphicsPath on a Panel. The GraphicsPath:s includes thousands of lines, and circles. It is also possible to draw lines and rectangles when the whole figure is shown on screen, it then updates one of the GraphicsPath:s using mouse-position. The problem is that it causes flickering when the screen is been redrawn. Anyone got a solution for this ?


    This is continued from Flicker free painting http://social.msdn.microsoft.com/Forums/en-US/winforms/thread/aaed00ce-4bc9-424e-8c05-c30213171c2c#7464f7d7-b337-4876-a16e-7df2320571f0

    I handle the update of screen by this program, it recalculates resolution also because the window can be resized also and then it should change scale for drawing.

     

    Private Sub panDraw_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles panDraw.Paint

     

    'Ratio = (panDraw.Height) / (panDraw.Width)

    DPanel.mm.korkeusKuvanSiirto = DPanel.mm.nollapisteY

    'DPanel.mm.korkeus

    DPanel.mm.leveysKuvanSiirto = DPanel.mm.nollapisteX

    e.Graphics.PageScale = DPanel.mm.Scale(panDraw, DPanel.mm.leveys)

    'laskee skaalauksen suhde

    DPanel.ScaleFactor = Val(e.Graphics.PageScale)

    e.Graphics.TranslateTransform(DPanel.mm.origoOffsetX, DPanel.mm.origoOffsetY)

    'panelin scrollauksen toteutus

    e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias

     

     

     

    PathToScreen(e) 'This subroutine draws all the paths, see below

    End
    Sub


     

    Private Sub PathToScreen(ByVal e As System.Windows.Forms.PaintEventArgs)

     

     

    DPanel.Draw(e, Pens.LightBlue, Drawboard.mousePath, 0, 0)

     

     

     

    End Sub

     

     

     

    The CreateParams (see the link on top for more info) helps on Vista, but on XP-machine it did flickering very bad. Tried to switch on doublebuffering but that didn´t help on this case.

    Protected

     

    Overrides ReadOnly Property CreateParams() As CreateParams

     

    'http://social.msdn.microsoft.com/forums/en-US/winforms/thread/aaed00ce-4bc9-424e-8c05-c30213171c2c/?prof=required&ppud=4

     

    Get

     

    Dim cp As CreateParams = MyBase.CreateParams

    cp.ExStyle = cp.ExStyle

    Or &H2000000

     

    Return cp

     

    End Get

     

    End Property 'CreateParams

    DPanel.DrawFill(e, Brushes.Blue, Drawboard.mittatekstipath, 0, 0)

    DPanel.Draw(e, Pens.Blue, Drawboard.mittapath, 0, 0)

    DPanel.Draw(e, Pens.Blue, Drawboard.painopath, 0, 0)

    DPanel.Draw(e, Pens.Red, Drawboard.CabPath, 0, 0)

    DPanel.Draw(e, Pens.Black, Drawboard.chassispath, 0, 0)

    DPanel.Draw(e, Pens.Black, Drawboard.logopath, 0, 0)

    DPanel.Draw(e, Pens.Brown, Drawboard.bodypath, 0, 0)

    DPanel.Draw(e, Pens.Brown, Drawboard.subframepath, 0, 0)

     

     

    DPanel.mm.korkeus = DPanel.mm.leveys * DPanel.px.korkeus_suhde(panDraw)

    • Edited by RCazzo Thursday, July 30, 2009 7:42 AM
    Thursday, July 30, 2009 7:28 AM

Answers

  • Friend Class BufferedPanel
      Inherits Panel
      Public Sub New()
        Me.DoubleBuffered = True
      End Sub
    End Class
    Hans Passant.
    • Marked as answer by RCazzo Wednesday, August 5, 2009 9:12 AM
    Thursday, July 30, 2009 12:28 PM
  • Hi RCazzo,
     
     

    Thanks for the sample code. It really helps me to understand the problem you are facing. Currently, based on my reasearch, I find it's a known issue internally that PageScale property will not take effect when DoubleBuffered property is set to true. To workaround this problem, we can use the ScaleTransform method instead of setting PageScale property. Please apply the following change:

       Private Sub panDraw_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles panDraw.Paint
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            'e.Graphics.PageScale = 0.087
            e.Graphics.ScaleTransform(0.087F, 0.087F)
            PathToScreen(e)
        End Sub

     
    If the problem can't be solved or any further problem, please feel free to let me know.

     

    Best regards,

    Bruce Zhou

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.

    • Edited by Bruce.Zhou Wednesday, August 5, 2009 5:49 AM
    • Marked as answer by RCazzo Wednesday, August 5, 2009 9:13 AM
    Wednesday, August 5, 2009 5:42 AM

All replies

  • Your problem is simply solved by using a double-buffered panel.  Check this thread.

    Hans Passant.
    Thursday, July 30, 2009 10:39 AM
  • Sorry for my stupidness, but I can´t figure out how to implement this in my VB6 code.
    Thursday, July 30, 2009 11:03 AM
  • You cannot implement it in VB6.  This forums site only supports .NET.  Come back after you upgraded your tools.

    Hans Passant.
    Thursday, July 30, 2009 11:43 AM
  • Sorry, I mixed up versions, I earlier posted about VB6 problem and therefore I wrote wrong version here.
    I have VB.NET 2008 in use and this problem relates to .NET version.
    Thursday, July 30, 2009 12:19 PM
  • Friend Class BufferedPanel
      Inherits Panel
      Public Sub New()
        Me.DoubleBuffered = True
      End Sub
    End Class
    Hans Passant.
    • Marked as answer by RCazzo Wednesday, August 5, 2009 9:12 AM
    Thursday, July 30, 2009 12:28 PM
  • Ok, thanks nobugz for the code sample. I must tell you that I´m a newbie so I probably just don´t have done it right. Here´s what I tried to do:
    I added a new Class Bufferedpanel with your code
    then I changed the property my drawing panel (panDraw) from type System.Windows.Forms.Panel to Bufferedpanel by modifying type in Declaration.
    The result is that I can see a bit of the picture as background in two small textboxes that has transparent background but the rest of the panel remains empty.

     

    Me.panDraw = New Drawprogr.Bufferedpanel

     

    Friend WithEvents panDraw As Drawprogr.Bufferedpanel

    Friday, July 31, 2009 11:43 AM
  • You want to implement the Paint event.  Did you?

    Hans Passant.
    Friday, July 31, 2009 12:18 PM
  • implement ? Can you explain a bit
    Monday, August 3, 2009 6:24 AM
  • Hi RCazzo,

    >The result is that I can see a bit of the picture as background in two small textboxes that has transparent background but the rest of the panel remains empty.

    What's the problem when you are using double buffer? I can't have a clear picture of your problem from your description. Can you please create a small, ready-to-run application which can reproduce the problem.

    Here's the document on "How to: Reduce Graphics Flicker with Double Buffering for Forms and Controls ", For more complex scenarios, you may consider manually managing buffered graphics which you can refer to "How to: Manually Manage Buffered Graphics ".

    Hope it helps!

    Best regards,
    Bruce Zhou
    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Tuesday, August 4, 2009 2:04 AM
  • Public Class Form1
        Dim grPath As New Drawing2D.GraphicsPath
        Dim mousepath As New Drawing2D.GraphicsPath
        Dim xStart As Integer
        Dim yStart As Integer
    
        Private Sub panDraw_MouseDown(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles panDraw.MouseDown
            xStart = e.X
            yStart = e.Y
            System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Cross
            lblCoordXY.Text = "Start " & xStart & ", " & yStart
        End Sub
    
        Private Sub panDraw_MouseUp(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles panDraw.MouseUp
            Dim y
            Dim x
            If System.Windows.Forms.Cursor.Current = System.Windows.Forms.Cursors.Cross Then
                x = e.X
                y = e.Y
                lblCoordXY.Text = "x: " & x - xStart & " y: " & y - yStart
            End If
        End Sub
    
        Private Sub panDraw_MouseMove(ByVal sender As Object, ByVal e As Windows.Forms.MouseEventArgs) Handles panDraw.MouseMove
            Dim y
            Dim x
            Dim xlabel
            Dim ylabel
            x = e.X
            y = e.Y
            xlabel = x
            ylabel = y
            tbCoordinate.Text = x & " , " & y
            If System.Windows.Forms.Cursor.Current = Windows.Forms.Cursors.Cross Then
                mousepath.Reset()
                piirraLaatikko(mousepath, x, y)
                lblCoordXY.Text = ("x: " & x - xStart & " y: " & y - yStart).ToString
                lblCoordXY.Left = x
                lblCoordXY.Top = y
                If CInt(x - xStart) = 0 And CInt(y - yStart) = 0 Then
                    lblCoordXY.Visible = False
                Else
                    lblCoordXY.Visible = True
                End If    
                panDraw.Refresh()
            End If
        End Sub
    
        Public Sub piirraLaatikko(ByVal e As Drawing2D.GraphicsPath, ByVal x As Integer, ByVal y As Integer)
            Dim pathRect As New Rectangle
            pathRect.X = xStart
            pathRect.Width = x - xStart
            pathRect.Y = yStart
            pathRect.Height = y - yStart
            e.AddRectangle(pathRect)
        End Sub
    
        Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
            Dim rect As Rectangle
            For i = 1 To 10
                rect.X = 10 * i
                rect.Y = 10 * i
                rect.Width = 100 * i
                rect.Height = 100 * i
                grPath.AddRectangle(rect)
            Next
        End Sub
    
        Private Sub PathToScreen(ByVal e As System.Windows.Forms.PaintEventArgs)
            e.Graphics.DrawPath(Pens.Blue, grPath)
            e.Graphics.DrawPath(Pens.Red, mousepath)
        End Sub
    
    
        Private Sub panDraw_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles panDraw.Paint
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            e.Graphics.PageScale = 0.087
            PathToScreen(e)
        End Sub
    
    End Class
    Buffered panel:
    Friend Class Bufferedpanel
        Inherits Panel
        Public Sub New()
            Me.DoubleBuffered = True
        End Sub
    End Class

    Hi Bruce,
    thanks to your advice to make a small demo of the effect I now have a bit more knowledge of the problem.
    This little program has a form with a panel with one label and one textbox. It draws 10 rectangles into graphicspath on start and shows coordinates on mousemove over the panel. When pressing mouse.left it starts to draw a rectangle (only downwards and to the right here in the test version). When starting up the program with a regular panel the rectangles are scaling down and are shown in the top-left corner of the window, if you press mouse.left and drag you will see the flickering when drawing on the blue rectangles.
    If you change the system.windows.forms.panel to the friend-class type doublebuffer:

     

    Me.panDraw = New System.Windows.Forms.Panel -> to:

     

    Me.panDraw = New Bufferedpanel


    and:

     

    Friend WithEvents panDraw As System.Windows.Forms.Panel -> to:

     

    Friend WithEvents pandraw As Bufferedpanel

    and re-run the program you will discover that the rectangles are over the whole screen now, but flicker is gone ! So my REAL problem is the  

    e.Graphics.PageScale = 0.087

     

    that will not have any effect when I doublebuffer the panel.

    that will not have any effect when I doublebuffer the panel.

     

     

    • Edited by RCazzo Tuesday, August 4, 2009 12:36 PM
    Tuesday, August 4, 2009 12:24 PM
  • Food for thought.....courtesy of Hans a couple of weeks ago.....

    Public Class DragForm
        Inherits Form
        ' Methods
        Public Sub New()
            Me.InitializeComponent()
            Me.DoubleBuffered = True
            Me.mPiece = New Bitmap(30, 30)
            Me.mPiecePos = New Point(((MyBase.ClientSize.Width / 2) - 15), ((MyBase.ClientSize.Height / 2) - 15))
            Using gr As Graphics = Graphics.FromImage(Me.mPiece)
                gr.Clear(Me.BackColor)
                gr.FillEllipse(Brushes.Red, New Rectangle(0, 0, Me.mPiece.Width, Me.mPiece.Height))
            End Using
        End Sub

        Protected Overrides Sub Dispose(ByVal disposing As Boolean)
            If (disposing AndAlso (Not Me.components Is Nothing)) Then
                Me.components.Dispose()
            End If
            MyBase.Dispose(disposing)
        End Sub

        Private Sub InitializeComponent()
            Me.components = New System.ComponentModel.Container
            MyBase.AutoScaleMode = AutoScaleMode.Font
            Me.Text = "Form4"
        End Sub

        Protected Overrides Sub OnMouseDown(ByVal e As MouseEventArgs)
            If ((((e.X >= Me.mPiecePos.X) AndAlso (e.X < (Me.mPiecePos.X + Me.mPiece.Width))) AndAlso (e.Y >= Me.mPiecePos.Y)) AndAlso (e.Y < (Me.mPiecePos.Y + Me.mPiece.Height))) Then
                Me.mMoving = True
                Me.mMousePos = e.Location
                Cursor.Hide()
            End If
        End Sub

        Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
            If Me.mMoving Then
                Me.mPiecePos.X = (Me.mPiecePos.X + (e.X - Me.mMousePos.X))
                Me.mPiecePos.Y = (Me.mPiecePos.Y + (e.Y - Me.mMousePos.Y))
                Me.mMousePos = e.Location
                MyBase.Invalidate()  ' Forces call to OnPaint to occur.
            End If
        End Sub

        Protected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
            If Me.mMoving Then
                Me.mMoving = False
                Cursor.Show()
            End If
        End Sub

        Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)
            e.Graphics.DrawImage(Me.mPiece, Me.mPiecePos)
        End Sub


        ' Fields
        Private components As System.ComponentModel.IContainer = Nothing
        Private mMousePos As Point
        Private mMoving As Boolean
        Private mPiece As Bitmap
        Private mPiecePos As Point
    End Class

     


    Mark the best replies as answers. "Fooling computers since 1971."
    Tuesday, August 4, 2009 6:00 PM
  • Hi RCazzo,
     
     

    Thanks for the sample code. It really helps me to understand the problem you are facing. Currently, based on my reasearch, I find it's a known issue internally that PageScale property will not take effect when DoubleBuffered property is set to true. To workaround this problem, we can use the ScaleTransform method instead of setting PageScale property. Please apply the following change:

       Private Sub panDraw_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles panDraw.Paint
            e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            'e.Graphics.PageScale = 0.087
            e.Graphics.ScaleTransform(0.087F, 0.087F)
            PathToScreen(e)
        End Sub

     
    If the problem can't be solved or any further problem, please feel free to let me know.

     

    Best regards,

    Bruce Zhou

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.

    • Edited by Bruce.Zhou Wednesday, August 5, 2009 5:49 AM
    • Marked as answer by RCazzo Wednesday, August 5, 2009 9:13 AM
    Wednesday, August 5, 2009 5:42 AM
  • Thanks Bruce !
    That really did the trick ! One other thing came up with ScaleTransform, as you see the small rectangle isn´t drawn at right position now. It can be solved by adding the same scalefactor to the MouseEventArgs :

                x = e.X / 0.087
                y = e.Y / 0.087
    but is there any better way to do it ? In the big program the scalefactor is not always the same and I will be connecting a lot of functions to MouseEventArgs.
    Wednesday, August 5, 2009 7:09 AM
  • Hi RCazzo,

     

    I am not sure I get you fully. Why not create a constant variable in the application so that you don’t need to worry about changing the scalefactor in many spaces?

     

    Best regards,

    Bruce Zhou

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com

     


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, August 5, 2009 7:23 AM
  • Yes, that´s a way it could be done. I thought another way to somehow override the e.x and e.y in mouseventargs and add the scalefactor there. That way I don´t have to worry about the scalefactor when building more functions.
    Wednesday, August 5, 2009 7:42 AM
  • Hi RCazzo,

     

    Ok, did you have problem when you are implementing that?

     

    Best regards,

    Bruce Zhou

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, August 5, 2009 8:13 AM
  • Hi Bruce,
    not any big problem but I have to take the scalefactor in components I'm placing on the drawing area (like labels, texboxes etc) but that´s just coding.

    Thanks a lot for the help, it really made my day to get rid of the flicker problem !
    Wednesday, August 5, 2009 8:18 AM
  • Hi RCazzo,

     

    You are welcome. If you have any further problems, please feel free to contact me.

     

    Best regards,

    Bruce Zhou

    MSDN Subscriber Support in Forum

    If you have any feedback on our support, please contact msdnmg@microsoft.com


    Please remember to mark the replies as answers if they help and unmark them if they provide no help.
    Welcome to the All-In-One Code Framework! If you have any feedback, please tell us.
    Wednesday, August 5, 2009 8:21 AM