smooth progress bar flickering

  • Thread starter Thread starter Brian Henry
  • Start date Start date
B

Brian Henry

I created a smooth progress bar with this code.. but if you update the
values in a row quickly of it and watch it on screen it flickers... how
would i change this to reduce the flickering? thanks...

Imports System

Imports System.Drawing

Imports System.Drawing.Drawing2D

Imports System.Text

Imports System.Windows.Forms

Public Class SmoothProgressBar

Inherits System.Windows.Forms.UserControl

#Region " Windows Form Designer generated code "

Public Sub New()

MyBase.New()

'This call is required by the Windows Form Designer.

InitializeComponent()

'Add any initialization after the InitializeComponent() call

Me.SetStyle(ControlStyles.DoubleBuffer, True)

Me.UpdateStyles()



End Sub

'UserControl overrides dispose to clean up the component list.

Protected Overloads Overrides Sub Dispose(ByVal disposing As Boolean)

If disposing Then

If Not (components Is Nothing) Then

components.Dispose()

End If

End If

MyBase.Dispose(disposing)

End Sub

'Required by the Windows Form Designer

Private components As System.ComponentModel.IContainer

'NOTE: The following procedure is required by the Windows Form Designer

'It can be modified using the Windows Form Designer.

'Do not modify it using the code editor.

<System.Diagnostics.DebuggerStepThrough()> Private Sub InitializeComponent()

'

'SmoothProgressBar

'

Me.Name = "SmoothProgressBar"

Me.Size = New System.Drawing.Size(208, 21)

End Sub

#End Region

Private min As Integer = 0 ' Minimum value for progress range

Private max As Integer = 100 ' Maximum value for progress range

Private val As Integer = 0 ' Current progress

Private barColor As Color = Color.Blue ' Color of progress meter



Protected Overrides Sub OnResize(ByVal e As EventArgs)

' Invalidate the control to get a repaint.

Me.Invalidate()

End Sub

Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)

Dim g As Graphics = e.Graphics

Dim brush As SolidBrush = New SolidBrush(barColor)

Dim percent As Double = (val - min) / (max - min)

Dim rect As Rectangle = Me.ClientRectangle

Dim size As SizeF = (e.Graphics.MeasureString((percent * 100).ToString &
"%", Me.Font, Me.Width))

Dim middleX As Integer = CInt(((Me.Width - size.Width) / 2))

Dim middleY As Integer = CInt(((Me.Height - size.Height) / 2))

' Calculate area for drawing the progress.

rect.Width = CInt(rect.Width * percent)

' Draw the progress meter.

g.FillRectangle(brush, rect)

e.Graphics.DrawString((percent * 100).ToString & "%", Me.Font, New
Drawing.SolidBrush(Color.FromArgb(75, 0, 0, 0)), middleX + 1, middleY + 1)

e.Graphics.DrawString((percent * 100).ToString & "%", Me.Font, New
Drawing.SolidBrush(Drawing.Color.White), middleX, middleY)



' Draw a three-dimensional border around the control.

Draw3DBorder(g)

' Clean up.

brush.Dispose()

g.Dispose()

End Sub

Public Property Minimum() As Integer

Get

Return min

End Get

Set(ByVal Value As Integer)

' Prevent a negative value.

If (Value < 0) Then

min = 0

End If

' Make sure that the minimum value is never set higher than the maximum
value.

If (Value > max) Then

min = Value

min = Value

End If

' Make sure that the value is still in range.

If (val < min) Then

val = min

End If







' Invalidate the control to get a repaint.

Me.Invalidate()

End Set

End Property

Public Property Maximum() As Integer

Get

Return max

End Get

Set(ByVal Value As Integer)

' Make sure that the maximum value is never set lower than the minimum
value.

If (Value < min) Then

min = Value

End If

max = Value

' Make sure that the value is still in range.

If (val > max) Then

val = max

End If

' Invalidate the control to get a repaint.

Me.Invalidate()

End Set

End Property

Public Property Value() As Integer

Get

Return val

End Get

Set(ByVal Value As Integer)

Dim oldValue As Integer = val

' Make sure that the value does not stray outside the valid range.

If (Value < min) Then

val = min

ElseIf (Value > max) Then

val = max

Else

val = Value

End If

' Invalidate only the changed area.

Dim percent As Double

Dim newValueRect As Rectangle = Me.ClientRectangle

Dim oldValueRect As Rectangle = Me.ClientRectangle

' Use a new value to calculate the rectangle for progress.

percent = (val - min) / (max - min)

newValueRect.Width = CInt(newValueRect.Width * percent)

' Use an old value to calculate the rectangle for progress.

percent = (oldValue - min) / (max - min)

oldValueRect.Width = CInt(oldValueRect.Width * percent)

Dim updateRect As Rectangle = New Rectangle

' Find only the part of the screen that must be updated.

If (newValueRect.Width > oldValueRect.Width) Then

updateRect.X = oldValueRect.Size.Width

updateRect.Width = newValueRect.Width - oldValueRect.Width

Else

updateRect.X = newValueRect.Size.Width

updateRect.Width = oldValueRect.Width - newValueRect.Width

End If

updateRect.Height = Me.Height

' Invalidate only the intersection region.

Me.Invalidate(Me.ClientRectangle)

Me.Update()

' Me.Invalidate(True)

End Set

End Property

Public Property ProgressBarColor() As Color

Get

Return barColor

End Get

Set(ByVal Value As Color)

barColor = Value

' Invalidate the control to get a repaint.

Me.Invalidate()

End Set

End Property

Private Sub Draw3DBorder(ByVal g As Graphics)

Dim PenWidth As Single = Pens.White.Width

g.DrawLine(Pens.DarkGray, _

New Point(Me.ClientRectangle.Left, Me.ClientRectangle.Top), _

New Point(CInt(Me.ClientRectangle.Width - PenWidth),
Me.ClientRectangle.Top))

g.DrawLine(Pens.DarkGray, _

New Point(Me.ClientRectangle.Left, Me.ClientRectangle.Top), _

New Point(Me.ClientRectangle.Left, CInt(Me.ClientRectangle.Height -
PenWidth)))

g.DrawLine(Pens.White, _

New Point(Me.ClientRectangle.Left, CInt(Me.ClientRectangle.Height -
PenWidth)), _

New Point(CInt(Me.ClientRectangle.Width - PenWidth),
CInt(Me.ClientRectangle.Height - PenWidth)))

g.DrawLine(Pens.White, _

New Point(CInt(Me.ClientRectangle.Width - PenWidth),
Me.ClientRectangle.Top), _

New Point(CInt(Me.ClientRectangle.Width - PenWidth),
CInt(Me.ClientRectangle.Height - PenWidth)))

End Sub

Private Sub SmoothProgressBar_Load(ByVal sender As System.Object, ByVal e As
System.EventArgs) Handles MyBase.Load

End Sub

End Class
 
I created a smooth progress bar with this code.. but if you update the
values in a row quickly of it and watch it on screen it flickers... how
would i change this to reduce the flickering? thanks...

I didn't scan the code in its entirety, but I have a suggestion which may
apply. If you are clearing the drawing area every time you draw a new
value...don't! This is most likely what is causing the flicker. Keep
internal variables that know what the old value was and clear the drawing
area only if the progress bar is getting smaller. Otherwise just draw over
what's already there.
 
that was something I did for debugging the flickering... forgot to take it
out and put the update Rectangle back around the updated area to
invalidate... but after changeing it back it still flickers... and when i
add this to my load event

Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint Or
ControlStyles.DoubleBuffer, True)

Me.SetStyle(ControlStyles.ResizeRedraw, True)

Me.UpdateStyles()



it crashes with this error



MESSAGE: Invalid parameter used.

TYPE: System.ArgumentException

SOURCE: System.Drawing

TARGET SITE: Void EndContainer(System.Drawing.Drawing2D.GraphicsContainer)

MSDN HELP LINK:

HASH CODE: 139

BASE EXCEPTION: System.ArgumentException: Invalid parameter used.
at System.Drawing.Graphics.EndContainer(GraphicsContainer container)
at
System.Windows.Forms.DibGraphicsBufferManager.ReleaseBuffer(GraphicsBuffer
buffer)
at System.Windows.Forms.GraphicsBuffer.Dispose()
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.UserControl.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Benefits.clsMain.Main() in C:\RESCHINIDEV\BENEFITS
APPLICATION\BenefitsApp\clsMain.vb:line 116

INNER EXCEPTION:

STACK TRACE: at System.Drawing.Graphics.EndContainer(GraphicsContainer
container)
at
System.Windows.Forms.DibGraphicsBufferManager.ReleaseBuffer(GraphicsBuffer
buffer)
at System.Windows.Forms.GraphicsBuffer.Dispose()
at System.Windows.Forms.Control.WmPaint(Message& m)
at System.Windows.Forms.Control.WndProc(Message& m)
at System.Windows.Forms.ScrollableControl.WndProc(Message& m)
at System.Windows.Forms.ContainerControl.WndProc(Message& m)
at System.Windows.Forms.UserControl.WndProc(Message& m)
at System.Windows.Forms.ControlNativeWindow.OnMessage(Message& m)
at System.Windows.Forms.ControlNativeWindow.WndProc(Message& m)
at System.Windows.Forms.NativeWindow.DebuggableCallback(IntPtr hWnd,
Int32 msg, IntPtr wparam, IntPtr lparam)
at System.Windows.Forms.UnsafeNativeMethods.DispatchMessageW(MSG& msg)
at
System.Windows.Forms.ComponentManager.System.Windows.Forms.UnsafeNativeMethods+IMsoComponentManager.FPushMessageLoop(Int32
dwComponentID, Int32 reason, Int32 pvLoopData)
at System.Windows.Forms.ThreadContext.RunMessageLoopInner(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.ThreadContext.RunMessageLoop(Int32 reason,
ApplicationContext context)
at System.Windows.Forms.Application.Run(ApplicationContext context)
at Benefits.clsMain.Main() in C:\RESCHINIDEV\BENEFITS
APPLICATION\BenefitsApp\clsMain.vb:line 116
 
Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint Or
ControlStyles.DoubleBuffer, True)


it crashes with this error

MESSAGE: Invalid parameter used.

You need to use AND instead of OR in the SetStyle statement. That should
get rid of the error.

--
Chris

dunawayc[AT]sbcglobal_lunchmeat_[DOT]net

To send me an E-mail, remove the "[", "]", underscores ,lunchmeat, and
replace certain words in my E-Mail address.
 
strange... well it no longer crashes even though MSDN states you should use
the OR gate not and, which is why I used it
(http://msdn.microsoft.com/library/d...stemwindowsformscontrolclasssetstyletopic.asp)

the flickering was reduced some, but still does it a little.. which im still
trying to get rid of..


Chris Dunaway said:
Me.SetStyle(ControlStyles.UserPaint Or ControlStyles.AllPaintingInWmPaint
Or
ControlStyles.DoubleBuffer, True)


it crashes with this error

MESSAGE: Invalid parameter used.

You need to use AND instead of OR in the SetStyle statement. That should
get rid of the error.

--
Chris

dunawayc[AT]sbcglobal_lunchmeat_[DOT]net

To send me an E-mail, remove the "[", "]", underscores ,lunchmeat, and
replace certain words in my E-Mail address.
 
Hi Peter,

I did that code and loaded my drawing code where it said to place it in the
2nd example they provided using the WM_SETREDRAW hook, but all that did was
cause the drawing not to work at all in the update... I also, as stated in
the other replys in this thread tried double buffering and flickers yet...
 
Hi Brian,

I think the document is right, we need to use the OR when we need to
applied more than one styles at one time.

As fro the excpetion, I suspect the issue is caused by you disposed the
e.Graphics object in your Paint event. I can reproduce this issue with only
this line in paint event.

You may not dispose the e.Graphics object, the underlying winform code
still needs it after returning from your event handler, and the underlying
code will dispose it finally.

Accidentally, the dispose method does not cause trouble when the control
does not have AllPaintingInWmPaint and double buffer styles.

Does it resolve your problem after removing the line g.Dispose() in the
OnPaint method? If the problem still exists , please feel free to reply
this thread to let me know and send that test program to me to let me take
a look.


Best regards,

Peter Huang
Microsoft Online Partner Support

Get Secure! - www.microsoft.com/security
This posting is provided "AS IS" with no warranties, and confers no rights.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Back
Top