Click here to Skip to main content
15,886,258 members
Please Sign up or sign in to vote.
0.00/5 (No votes)
See more:
Hello,

Im sure this is simple, but after confusing myself searching around for the correct answer I thought it best to ask....

Here's what I have: A full screen app with lots of timer based sampling and graphical display of values alongside which I wanted a circular type progress bar. I searched around and found a really neat solution (thanks to Matt Wilko):

VB
Private Sub DrawProgress(g As Graphics, rect As Rectangle, percentage As Single)
        'Draws the circular progress counter
        'work out the angles for each arc
        Dim progressAngle = CSng(360 / 100 * percentage)
        Dim remainderAngle = 360 - progressAngle

        'create pens to use for the arcs
        Using progressPen As New Pen(ThmVSEndColNormal, 4), remainderPen As New Pen(ThmTextColBody, 4)
            'set the smoothing to high quality for better output
            g.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
            'draw the arcs
            g.DrawArc(progressPen, rect, -90, progressAngle)
            g.DrawArc(remainderPen, rect, progressAngle - 90, remainderAngle)
        End Using

        'draw the text in the centre by working out how big it is and adjusting the co-ordinates accordingly
        Using fnt As New Font(Me.Font.FontFamily, 14)
            Dim text As String = percentage.ToString + "%"
            Dim textSize = g.MeasureString(text, fnt)
            Dim textPoint As New Point(CInt(rect.Left + (rect.Width / 2) - (textSize.Width / 2)), CInt(rect.Top + (rect.Height / 2) - (textSize.Height / 2)))
            'now we have all the values draw the text
            g.DrawString(text, fnt, Brushes.White, textPoint)
        End Using
    End Sub


In the example Matt calls the routine in the Paint event thus:

DrawProgress(e.Graphics, New Rectangle(GrpControl.Left + 15, GrpControl.Top + ProgCountDown.Top, ProgCountDown.Height, ProgCountDown.Height), 40)


where 40 is the value required, its static here but obviously needs to change.

Now, I can assign a global variable to the percentage I need, send that off to the 'DrawProgress' sub and then refresh or invalidate the the form each time the value changes which does work, but the whole screen and all the controls refresh causing a nasty jitter.

I'm still getting to grips with .net so forgive my lack of understanding, but I could do with some advice on how to handle this properly. It seems to me that I perhaps need to invalidate just the graphics object created in the DrawProgress sub so Im not forcing the whole screen to re-paint.

Eventually I'd like to make control class for this circular progress bar as it's really neat and I'll use it a lot but that's for another day....
Posted
Comments
Ralf Meier 3-Aug-15 8:19am    
If I understood it right :

The Painting-Method itself is working properly.
The Painting-Method is called by a Timer.Tick or the Timer.Tick calls an Control.Invalidate - how often ?
Why is the whole Screen invalidated ? You only need to invalidate the control.

Perhaps you should show the code from the complete control ...
SheepRustler 3-Aug-15 8:52am    
Hi Ralf,
Yes, I can trigger the form Paint event by invalidating the form on one of the timers (once per second), but the whole screen flickers badly each time the whole screen re-paints, so I guess I want to just invalidate the graphics (arcs and text) created in the 'DrawProgress' sub.

This is what I cannot figure out how to do as they are created at runtime from within the 'DrawProgess' sub and not placed as controls during design time.

Thanks


Ralf Meier 3-Aug-15 9:00am    
see my answer and the Suggestion in it.
Are you able to realize it like described by me ?

1 solution

OK ... I searched a little around and found it here : http://stackoverflow.com/questions/26928523/visual-basic-circular-progress-bar[^]

Now I understand the Problem.
In this Suggestion the Progressbar ist painted on a Form - I think, you have done the same.
What you should do is :
Create a Class(-File) and name it.
This class should inherit from control.
Now place a Property in it to give it the percentage for the visualisation.
Perhaps you want to have the controls-Background translucent - we could add it.
Override the OnPaint-Method in it and do it like in your form.
Perhaps you must modify the Resize-Event because you want to have a quadratic resizing.

But in effect : now you invalidate only the control and not the Form on which it is placed.
 
Share this answer
 
v2
Comments
SheepRustler 3-Aug-15 9:20am    
Thanks Ralf,
OK I'll try this. I've never created a class before so I'll have a go - there's a lot of new terminology for me here - 'inherit from control' and 'constructor' for example, but I'll have go... :)

Thanks again....
SheepRustler 3-Aug-15 11:55am    
Ralf,

I'm struggling this ! I think I'm nearly there but I just can't get the control to respond. I have created (I think) a DLL class and can now add the control to my Toolbox list of controls and so onto my form.

here's the class code:
Imports System.Windows.Forms
Imports System.Drawing

Public Class CircProgBar
'This Class creates a Circular progress bar based on:
'http://stackoverflow.com/questions/26928523/visual-basic-circular-progress-bar
Inherits ProgressBar

Private xPos As Integer = 0
Private yPos As Integer = 0
Private mWidth As Integer = 60
Private mHeight As Integer = 60
Private mPercent As Integer = 0
Private ColCount As Color = Color.Blue
Private ColRemain As Color = Color.White

Public Property GetX As Integer
Get
GetX = xPos
End Get
Set(value As Integer)
xPos = value
End Set
End Property
Public Property GetY As Integer
Get
GetY = yPos
End Get
Set(value As Integer)
yPos = value
End Set
End Property
Public Property GetHeight As Integer
Get
GetHeight = mHeight
End Get
Set(value As Integer)
mHeight = value
End Set
End Property

Public Property GetWidth As Integer
Get
GetWidth = mWidth
End Get
Set(value As Integer)
mHeight = value
End Set
End Property

Public Property GetPercent As Integer
Get
GetPercent = mPercent
End Get
Set(value As Integer)
mPercent = value
End Set
End Property
Public Property CountCol As Color
Get
CountCol = ColCount
End Get
Set(value As Color)
ColCount = value
End Set
End Property
Public Property RemainCol As Color
Get
RemainCol = ColRemain
End Get
Set(value As Color)
ColRemain = value
End Set
End Property
Protected Overrides Sub OnPaint(ByVal pEvent As PaintEventArgs)
'work out the angles for each arc
Dim progressAngle = CSng(360 / 100 * mPercent)
Dim remainderAngle = 360 - progressAngle
Dim rect As New Rectangle(xPos, yPos, mWidth, mHeight)
MyBase.OnPaint(pEvent)

'create pens to use for the arcs
Using progressPen As New Pen(ColCount, 4), remainderPen As New Pen(ColRemain, 4)
'set the smoothing to high quality for better output
pEvent.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
'draw the blue and white arcs
pEvent.Graphics.DrawArc(progressPen, rect, -90, progressAngle)
pEvent.Graphics.DrawArc(remainderPen, rect, progressAngle - 90, remainderAngle)
End Using

'draw the text in the centre by working out how big it is and adjusting the co-ordinates accordingly
Using fnt As New Font(Me.Font.FontFamily, 14)
Dim text As String = mPercent.ToString + "%"
Dim textSize = pEvent.Graphics.MeasureString(text, fnt)
Dim textPoint As New Point(CInt(rect.Left + (rect.Width / 2) - (textSize.Width / 2)), CInt(rect.Top + (rect.Height / 2) - (textSize.Height / 2)))
'now we have all the values draw the text
pEvent.Graphics.DrawString(text, fnt, Brushes.White, textPoint)
End Using

End Sub



End Class

In my application I drag a new control onto my form but when try to set up the control using the following:
Dim CP As CircProgBar.CircProgBar = DirectCast(CircProgBar1, CircProgBar.CircProgBar)
CP.GetX = 15
CP.GetY = ProgCountDown.Top
CP.GetHeight = ProgCountDown.Height
CP.GetWidth = CP.GetHeight
CP.GetPercent = 0
CP.Refresh()

It doesn't seem to have any effect, no compile errors but just a unformatted CircProgbar1 control.

Any clues?

Thanks
Ralf Meier 3-Aug-15 14:13pm    
Hi Stephen,
I think, you made a very good job.
The only thing, you forgot, was "me.invalidate".
You should put it into each setter from your Properties. This tells the Control that it must paint itself new.

It must be look like this :
Public Property GetPercent As Integer
Get
GetPercent = mPercent
End Get
Set(value As Integer)
mPercent = value
me.invalidate
End Set
End Property

It is also not necessary to inherit from Progressbar - you could also (I think it is much better cause of the lower level) to inherit from Control. Try it ...

Would you do me the favour and accept formally my answer (and perhaps, if you like, rate it) ?

Would you like to see some possible improvements ?
SheepRustler 3-Aug-15 15:59pm    
Thanks Ralf,
One step closer. I now see my control as it should be during design time - changing the parameters in the Control properties changes the control appearance during design time. Great, but in runtime the control appears as a solid grey square - something to do with transparency in my class perhaps ?

I'm beginning to understand the concept of classes much better now, thanks to your explanations.

EDIT: Yes, I'd be be pleased to see some suggestions for improving things....
Ralf Meier 3-Aug-15 16:15pm    
Which is your actual base-control ?
Still "ProgressBar" - or did you change it to "Control" ?

This content, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)



CodeProject, 20 Bay Street, 11th Floor Toronto, Ontario, Canada M5J 2N8 +1 (416) 849-8900