Author Topic: Circular Progress Bar  (Read 1965 times)

Phrog30

  • Guest
Circular Progress Bar
« on: May 03, 2017, 11:49:48 AM »
If anyone is interested, here is a circular progress bar, work in progress.  There is still quite a bit of work to do to make it more user friendly.  My main problem now is flickering.  I would appreciate some help on how to eliminate the flicker.  This might be something that could be included in the base package if Archie is onboard.

James

Phrog30

  • Guest
Re: Circular Progress Bar
« Reply #1 on: May 03, 2017, 02:05:15 PM »
Looks like this massive amount of code fixed the flicker....
Code: [Select]
Public Sub New()
        Me.DoubleBuffered = True
    End Sub

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Circular Progress Bar
« Reply #2 on: May 03, 2017, 02:14:17 PM »
Here is an updated version that fixes the flicker and masks the drawing region to a circle which allows other controls to overlap the corner regions. I also made it lighter weight by inheriting from Control instead of being based on UserControl. Once the control is finished being refined, I can add it to the normal project distribution,

Phrog30

  • Guest
Re: Circular Progress Bar
« Reply #3 on: May 03, 2017, 03:03:16 PM »
Thanks Archie, here is my update as well.  I changed a few things in the draw event, so it would draw in the center.  I assume best practice is to mimic the progressbar, as this one right now is strictly 0-100 on the value?

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Circular Progress Bar
« Reply #4 on: May 03, 2017, 03:29:40 PM »
Added a Maximum property
Added ValueChanged event
Made CenterPoint a class scope variable and calculate only in SizeChanged to do less calculation in the paint event

Phrog30

  • Guest
Re: Circular Progress Bar
« Reply #5 on: May 03, 2017, 06:32:35 PM »
I took your latest and added a minimum, which will allow scaling from a negative if the needs arises (the circle is still based on 0-100% for the fill).  I figure this object could be used as a dashboard item.  Thanks for your input on this.  One question, how hard is it, if even possible, to add thresholds that are dynamic?  So, if I wanted to created 3 thresholds that would change the color based on the value.  I know this is simple in code, but was wondering about properties.  So, is it possible to have a property that controls how many thresholds, then dynamically creates properties that allows to setup those thresholds.

Oh, one other question, on a property like:

Code: [Select]
Private m_Maximum As Integer = 100
    Public Property Maximum As Integer
        Get
            Return m_Maximum
        End Get
        Set(ByVal value As Integer)
            m_Maximum = value
            Invalidate()
        End Set
    End Property

I was using "Maximum" in my code, I noticed you are using "m_Maximum".  Both work, so what is the difference and is it important to do it the way you have?  I know a lot of this is based on standards, which as you can see I'm still far from understanding.


James

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Circular Progress Bar
« Reply #6 on: May 03, 2017, 06:46:02 PM »
Oh, one other question, on a property like:

Code: [Select]
Private m_Maximum As Integer = 100
    Public Property Maximum As Integer
        Get
            Return m_Maximum
        End Get
        Set(ByVal value As Integer)
            m_Maximum = value
            Invalidate()
        End Set
    End Property

I was using "Maximum" in my code, I noticed you are using "m_Maximum".  Both work, so what is the difference and is it important to do it the way you have?  I know a lot of this is based on standards, which as you can see I'm still far from understanding.
Using m_Maximum goes directly to the variable which is slightly more efficient that going through the Getter which is a function call. You have to be careful when setting the value because sometimes your Property Setter will validate the value before putting it into the variable. In that case you want to use Maximum so you don't have duplicate the validating code.

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Circular Progress Bar
« Reply #7 on: May 03, 2017, 06:52:19 PM »
One question, how hard is it, if even possible, to add thresholds that are dynamic?  So, if I wanted to created 3 thresholds that would change the color based on the value.  I know this is simple in code, but was wondering about properties.  So, is it possible to have a property that controls how many thresholds, then dynamically creates properties that allows to setup those thresholds.
In this case you would want to use a collection, which is essentially a variable length array. This would allow you to add/remove items in the designer. This would be an example of how to do it:
Code: [Select]
    Private m_Thresholds As New System.Collections.ObjectModel.Collection(Of Integer)
    Public ReadOnly Property Thresholds As System.Collections.ObjectModel.Collection(Of Integer)
        Get
            Return m_Thresholds
        End Get
    End Property

Then m_Thresholds can be used as an array and use m_Thresholds.Count to get the number of items.

Phrog30

  • Guest
Re: Circular Progress Bar
« Reply #8 on: May 03, 2017, 08:11:46 PM »
Oh, one other question, on a property like:

Code: [Select]
Private m_Maximum As Integer = 100
    Public Property Maximum As Integer
        Get
            Return m_Maximum
        End Get
        Set(ByVal value As Integer)
            m_Maximum = value
            Invalidate()
        End Set
    End Property

I was using "Maximum" in my code, I noticed you are using "m_Maximum".  Both work, so what is the difference and is it important to do it the way you have?  I know a lot of this is based on standards, which as you can see I'm still far from understanding.
Using m_Maximum goes directly to the variable which is slightly more efficient that going through the Getter which is a function call. You have to be careful when setting the value because sometimes your Property Setter will validate the value before putting it into the variable. In that case you want to use Maximum so you don't have duplicate the validating code.

When you get a moment, can you give me an example using "Maximum" and validating code?  I'm not quite following what you wrote.

James

Archie

  • Administrator
  • Hero Member
  • *****
  • Posts: 5322
    • View Profile
    • AdvancedHMI
Re: Circular Progress Bar
« Reply #9 on: May 03, 2017, 08:46:59 PM »
For example let's say a value greater than 100 can crash the code some where in the class. In the Property Setter, you would ensure m_Maximum cannot be set to higher than 100. Since m_Maximum is Private, everything outside this class must use Maximum and therefore cannot circumvent this validation and crash the class. However with code inside the class, you would have to make sure to use Maximum instead of m_Maximum in order to make sure the value is validated.
Code: [Select]
Private m_Maximum As Integer = 100
    Public Property Maximum As Integer
        Get
            Return m_Maximum
        End Get
        Set(ByVal value As Integer)
            if value>100 then
                m_Maximum=100
            else
                m_Maximum = value
            End If
            Invalidate()
        End Set
    End Property

Phrog30

  • Guest
Re: Circular Progress Bar
« Reply #10 on: May 03, 2017, 10:01:09 PM »
For example let's say a value greater than 100 can crash the code some where in the class. In the Property Setter, you would ensure m_Maximum cannot be set to higher than 100. Since m_Maximum is Private, everything outside this class must use Maximum and therefore cannot circumvent this validation and crash the class. However with code inside the class, you would have to make sure to use Maximum instead of m_Maximum in order to make sure the value is validated.
Code: [Select]
Private m_Maximum As Integer = 100
    Public Property Maximum As Integer
        Get
            Return m_Maximum
        End Get
        Set(ByVal value As Integer)
            if value>100 then
                m_Maximum=100
            else
                m_Maximum = value
            End If
            Invalidate()
        End Set
    End Property

Got it.  Thanks for the explanation.