Answered by:
Problem with flickering screen when drawing on form

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
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
-
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 bitMonday, 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.
- 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 SubProtected 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 SubPrivate Sub InitializeComponent()
Me.components = New System.ComponentModel.Container
MyBase.AutoScaleMode = AutoScaleMode.Font
Me.Text = "Form4"
End SubProtected 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 SubProtected 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 SubProtected Overrides Sub OnMouseUp(ByVal e As MouseEventArgs)
If Me.mMoving Then
Me.mMoving = False
Cursor.Show()
End If
End SubProtected 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