当前位置:网站首页>[C] (original) step by step teach you to customize the control element - 04, ProgressBar (progress bar)

[C] (original) step by step teach you to customize the control element - 04, ProgressBar (progress bar)

2020-11-06 01:35:00 itread01

One 、 Preface

Technology is not advanced or backward , Only suitable and not suitable .

The custom control element in this article is : Progress bar (ProgressBar).

There are many ways to implement the progress bar , The mainstream way is : Use multiple images to achieve 、 Use 1 One or 2 One Panel Put it in UserControl Go up and realize 、 Overload system progress bar to achieve and so on .

The progress bar realized this time is still using GDI+ To achieve . Of course , If only to achieve the most basic flat progress bar , There's no need to write another article , Because I'm going to change the first one LTrackBar That's it .

Since writing this article , Is to achieve different 、 The progress and the fun are good , Like the circular progress bar 、 Pie shaped progress bar and so on .

The knowledge used in this article is what has been said in the previous chapters , There's no new technology . But with a little bit of imagination , Some of them are informal 、 A little bit beyond the conventional imagination .

 

I believe that after watching you , There will be gains .

This paper addresses :https://www.cnblogs.com/lesliexin/p/13575517.html


 

Two 、 Preliminary analysis

( One ) Why do you need to customize the progress bar ?

The scroll bar style of the system is too monotonous , At the same time, it's not enough “ flat ”, So go and implement your own scroll bar .

 

( Two ) Achieving the goal

1, Support three styles

(1) The bar (Bar)

 

(2) A round cake (Pie)

 

(3) Arc (Arc)

 

 

2, Support show and hide percentages

(1) The bar (Bar)

 

(2) A round cake (Pie)

 

(3) Arc (Arc)

 

 

3, Support multiple progress shapes

(1) Continuous

 

(2) Blocks

 

(3) Two stage formula : First block and then continuous

 

(4) screw

( notes : Only “ The bar ” The spiral shape is supported only when the style is used )

 

 

4, Support Marquee Style

When progress is uncertain , You need to use Marquee Style , Same as that of system progress bar “Marquee” The style is similar to .

But support more Marquee Style .

(1) Swing left and right

 

(2) Loop through

 

(3) Back and forth ( Continuous )

 

(4) Across ( Continuous )

 

(5) Back and forth ( Blocks )

 

(6) Across ( Blocks )

 

(7) screw

 

 

5, Support to adjust the size and color of each element in the progress bar

(1) Set border thickness and color

 

(2) Set the background size and color

 

(3) Set the progress drawing position and color

 

(4) Set progress text color

 

(5) Set the arc thickness ( Only the style is “ Arc (Arc)” It works )

 

(6) Set “ Blocks ” The thickness of the ( Only the progress bar shape is “ Blocks ” It works )

 

 


 

3、 ... and 、 The progress bar is disassembled

Look at the goal above , Do you feel dazzled 、 No way to start ?

Next, I will split the progress bar , Step by step to see how the above effect is achieved .

 

( One ) The constituent elements

The progress bar consists of three parts , The difference is : Progress 、 The border 、 background .

Here are the various styles , The separation of the three components .

1, The bar (Bar)

 

2, A round cake (Pie)

 

3, Arc (Arc)

 

 

( Two ) Element properties

The three elements of the progress bar , Each has its own attributes .

( notes : Because “ Color ” Attributes are necessary , So let's not go back to .)

1, The border

Its related properties are : The thickness of the border .

When “ The thickness of the ” For 0 When , It looks like the progress bar has no borders ;

When “ The thickness of the ” Over half of the height of the control element , The whole progress bar becomes the color of the border .

( notes : Because it's drawing first “ background ”, Draw again “ The border ”, So it is “ The whole progress bar becomes the color of the border ”)

A, For “ The bar (Bar)”, The thickness of its border is shown in the figure below :

B, For “ A round cake (Pie)”、“ Arc (Arc)”, The thickness of its border is shown in the figure below :

2, background

Its related properties are : The size of the background

The size of the background is the scope of the background rendering , Here's a homemade word “ Shrink width ” To describe .

When “ Shrink width ” For 0 When , Background size = The size of the control element itself ;

When “ Shrink width ” For x When , Background width = Control element width -2*x, Background height = Control element height -2*x;

When “ Shrink width ” Over half of the height of the control element , Background height = Control element height -2*( Control element height /2)=0, At this point, the progress bar will have no background .

A, For “ The bar (Bar)”, The contraction width is shown in the following figure :

B, For “ A round cake (Pie)”、“ Arc (Arc)”, The contraction width is shown in the following figure :

3, Progress

Its related attributes are : Progress mapping scope 、 Schedule style

A, Progress mapping scope

As the name suggests , It's the extent to which progress can be plotted , Here “ Draw border distance ” To describe .

When “ Draw border distance ” For 0 When , The extent to which progress is drawn = The size of the control element itself ;

When “ Draw border distance ” For x When , The starting point for drawing progress :(x,x), Draw the end point :( Control element width -x, Control element height -x), So draw the range =( Control element width -2*x, Control element height -2*x);

When “ Draw border distance ” Over half of the height of the control element , The drawing height of progress will be 0, It also means no progress .

A, For “ The bar (Bar)”, The drawing border distance is shown in the figure below :

B, For “ A round cake (Pie)”, The drawing border distance is shown in the figure below :

C, For “ Arc (Arc)”, The drawing border distance is shown in the figure below :

 

B, Schedule style

Progress style is the style of various progress in the previous section , There's continuous 、 With chunks 、 There are spirals and so on .

Most of this style knows how to implement it at first sight .

such as “ Continuous ”, stay “ The bar (Bar)” In the pattern , It's filling a rectangle ; stay “ A round cake (Pie)” in , It's filling a fan ; stay “ Arc (Arc)” in , It's drawing an arc .

such as “ Blocks ”, stay “ The bar (Bar)” In the pattern , It's filling multiple rectangles at equal intervals ; stay “ A round cake (Pie)” in , It's filling a fan at equal intervals ; stay “ Arc (Arc)” in , It's drawing an arc at equal intervals .

Here , I'm going to elaborate on a particular shape :“ screw ”, Because “ screw ” Except that it's not very intuitive to imagine , There are still a lot of details to deal with .

Because only “ The bar (Bar)” The style progress bar has “ screw ” Style , So the next explanation is to “ The bar (Bar)” Explain on the basis of .

At the same time , To avoid interference , The first two properties “ The border ” and “ background ” Will keep the default value , namely : No borders , Background size = Control element size .“ Progress mapping scope ” It's also the default value , That is to draw the range = Control element size .

(1)“ screw ” Pattern implementation explains

A, When the schedule is clear

That is, the progress is known and definite , such as 5%,33% wait . Its appearance is as follows :

 

Its schematic diagram is as follows :

 

And the blue parallelogram is “ screw ”, It's a background transparency in itself 、 There are several pictures of blue parallelograms on .

The increase or decrease of progress is essentially the left and right movement of the picture on the control element .

So , This picture should be the same size as the control element , Especially if the width is equal . But in use GDI+ To generate this image , But you can't make the width of the picture equal to the width of the control element .

When we draw parallelogram to the picture , It's drawn from right to left , The reason why I started drawing from the right side , To ensure that the style on the right side of the progress bar is fixed , Fixed in a more beautiful state . Because when the schedule changes , When the picture moves left and right , Our focus is on the right side , So a fixed right style is more important , Otherwise, when the width of the control element changes , The style on the right changes with it .

When the width of the picture is equal to the width of the control element , This will happen , That is, there is a blank space at the bottom right of the progress bar . As shown in the figure below :

 ( The graph above is the actual drawing picture , The picture below is to capture the picture , The same width as the progress bar )

So we make the width of the picture = The width of the control element +1 The width of the parallelogram . After drawing the picture , We took a picture from it that was the same width as the control element , So , The overall style is pretty good . As shown in the figure below :
 ( The graph above is the actual drawing picture , The picture below is to capture the picture , The same width as the progress bar )

 

To sum up , It's as shown in the figure below 5 Step by step :

 

 

B, When the progress is unknown

That is, the progress is uncertain , It's like the system progress bar Marquee The style is like that . Its appearance is as follows :

 

ditto , The top is still a transparent background 、 There are several pictures of blue parallelograms on . The effect of the image above is that the image moves in circles at different sections .

The details are as follows , The picture keeps moving to the right , When the right side has more than one equal quadrilateral , The picture is back in place , Then go back and forth .

 

Through the diagram above , We found a feature , The width of the picture is no longer equal to ( The width of the control element +1 The width of the parallelogram ), But wait for ( The width of the control element +2 The width of the parallelogram ). Here's why :

When drawing a diagram , For the convenience of visual inspection , A parallelogram is exactly two opposite right triangle rows , And when it's actually drawn , It's a rare style , Most of them are the shape of an equal quadrilateral formed by two opposite obtuse triangular rows , As shown in the figure below :

 

In this case , If the width of the picture = The width of the control element +1 The width of the parallelogram , Then there will be extra blank when moving to the far right and reset , As shown in the figure below :

 

therefore , Will make : The width of the picture = The width of the control element +2 The width of the parallelogram .

 

( 3、 ... and ) Other properties

In addition to the previous attributes directly related to the progress bar element , There are other attributes , These properties all work in a certain style .

1, Arc width

stay “ Arc (Arc)” In the progress bar of the style ,“ Progress ” It's an arc , So beyond the other attributes , We need more “ The width of the arc itself ” Such an attribute .

By default , Arc width = Control element width /10, Because when the schedule reaches 100% When , The arc becomes a circle , At this point, the area that appears to have an arc is one fifth of the width of the control element , It's a more conventional width .

By calling the arc width , Some special effects can be achieved .

 

 

2, Block width

In the progress style is “ Blocks ” When , To support different segment widths , So you have to have this attribute .

In order to create a better effect ,“ Block width ” It's not just the width of the colored part , It's for : The width of the colored part + Two color spaces .

After debugging , Discover when ( Color : Interval =2:1) When , The appearance is beautiful and natural .

therefore , One “ Block width ”=2/3 There's color width +1/3 No color width .

Because “ The bar (Bar)”、“ A round cake (Pie)”、“ Arc (Arc)” All support “ Blocks ”. So in “ The bar (Bar)” in ,“ Block width ” It means width ; And in the “ A round cake (Pie)”、“ Arc (Arc)” in ,“ Block width ” It's an angle .

 


 

Four 、 Start to realize

( One ) Preparatory work .

Here is just an outline , See the previous section for specific operation .

New class :LProgressBar.cs

New inheritance :Control( Need to add reference :System.Windows.Forms.dll)

Change the accessibility to :public

( Two ) New properties

1, Progress value

The progress value refers to the current progress , Here, the schedule range is fixed to :0~100.

The advantage of this is that it is easy to calculate and draw , It's also more intuitive to use .

2, Border thickness

See the explanation in the previous section for details .

( notes : I wrote the code first , And then write an article , Sometimes when writing an article, you will find that the naming of attributes is not very formal , such as “ Border thickness ” This property , use “BorderSize” Better , But when I write code, I think “ A circle of lines ”, So it's the picture below “SurroundLineSize”, But I found it hard to describe when I wrote the article , It's changed to “ Border thickness ”, But it doesn't make sense to modify the code again , What matters is the technological thinking itself . The same below .)

3, Border color

As the name suggests , It's the color of the border .

4, Background shrink width

See the explanation in the previous section for details .

5, Background color

6, Progress drawing range edge

See the explanation in the previous section for details .

7, Arc thickness

See the explanation in the previous section for details .

8, Progress color

Progress color is the color of progress itself .

9, Block width

See the explanation in the previous section for details .

10, Schedule style

Progress style describes the appearance of progress itself , If continuous 、 Blocks 、 Spiral and so on .

The schedule style is an enumeration , The details are as follows :

11, Progress bar type

Progress bar type refers to the style and appearance of progress bar , Like bars 、 A round cake 、 Arc, etc .

The progress bar type is an enumeration , The details are as follows :

12, Progress bar mode

Progress mode refers to whether the progress is definite or not .

The schedule is clear , For example, the current progress is 1%、45% wait .

The progress is not clear , For example, when you load a file, you load it all the time , But I don't know how much . This is the progress bar of the system Marquee Style .

The progress bar mode is an enumeration , The details are as follows :

13,Marquee Circle time

 Marquee Style is the speed of animation .

 

14,Marquees Style

Marquee Style animation .

 

The attribute is an enumeration , The details are as follows :

 

15,Marquee Type

Marquee The style is also animation , So support uniform speed and slow in and slow out effects .

 

The attribute is an enumeration , The details are as follows :

 

16, Progress text type

You can set whether the progress bar displays text , And whether the percentage is displayed .

 

The attribute is an enumeration , The details are as follows :

 

17, Progress text color

18, Construction function

In the constructor here , In addition to using the fixed “ Double buffering ” Outside , There are several additional properties set , These attributes are used to make control elements transparent , So the background color and foreground color can be transparent .

In this case , The whole control unit is like a completely transparent canvas , It's up to us to draw .

( 3、 ... and ) Rewriting methods

For the purpose of this schedule , Just to indicate progress information , So there's no need for events . Just rewrite the most basic OnPaint The method will do .

But , As a result of OnPaint There are too many styles and styles to draw in , So it's a lot of code , But the code is not very difficult . I'll start with OnPaint Put all the code in , Then I will focus on the principle of implementation .

and Marquee Style is essentially an animation effect , Circle to draw some figures or change the size and position of the figures , So we use a timer to trigger , To change the size or position of a figure at regular intervals . 

protected override void OnPaint(PaintEventArgs e)
{
    base.OnPaint(e);
    e.Graphics.SmoothingMode = SmoothingMode.HighQuality;

    // Progress actual drawing width 、 Height 
    float fRealWidth = Width - _DrawMargin * 2;
    float fRealHeight = Height - _DrawMargin * 2;

    float fRealLeftTop = _DrawMargin - 0.5f;
    if (fRealLeftTop < 0) fRealLeftTop = 0;

    // Keep it up, down, left and right 0.5 A picture element , Prevent trimming 
    bool bDrawSurroundLine = _SurroundLineSize > 0 ? true : false;
    bool bDrawInner = _ShrinkSize * 2 < Math.Min(Width, Height) ? true : false;
    float fSurroundLineSizeF = Convert.ToSingle(_SurroundLineSize);
    RectangleF rectInner = new RectangleF(_ShrinkSize, _ShrinkSize, (Width - 1) - _ShrinkSize * 2, (Height - 1) - _ShrinkSize * 2);
    RectangleF retcSurrondLine = new RectangleF(fSurroundLineSizeF / 2, fSurroundLineSizeF / 2, (Width - 1) - fSurroundLineSizeF, (Height - 1) - fSurroundLineSizeF);
    // The arc width is one tenth of the total width , Because it's an arc , So it turns out to be one in five 
    float fSurroundArcSize = _ArcSize > 0 ? _ArcSize : Width / 10;
    RectangleF retcSurrondArc = new RectangleF(fSurroundArcSize / 2 + fRealLeftTop, fSurroundArcSize / 2 + fRealLeftTop, (fRealWidth - 1) - fSurroundArcSize, (fRealHeight - 1) - fSurroundArcSize);

    SolidBrush sbInner = new SolidBrush(_ShrinkColor);
    SolidBrush sbFore = new SolidBrush(L_SliderColor);
    SolidBrush sbText = new SolidBrush(_TextColor);
    Pen penSurrondLine = new Pen(_SurroundLineColor, fSurroundLineSizeF);
    Pen penSurroundArc = new Pen(L_SliderColor, fSurroundArcSize);

    // The slider width is one fifth of the total width 
    float fSlider = Convert.ToSingle(fRealWidth) / 5;
    if (_ProgressType != ProgressType.Bar)
    {
        //360/5
        fSlider = 72;
    }

    float fRange = 0;
    if (L_MarqueeStyle == MarqueeStyle.Swing) fRange = fRealWidth - fSlider;
    else if (L_MarqueeStyle == MarqueeStyle.Cross) fRange = fRealWidth + fSlider;
    else fRange = fRealWidth;

    float fBlockSize = _BlockSize;
    if (fBlockSize < 3) fBlockSize = 3.0f;
    if (_ProgressType == ProgressType.Bar)
    {
        if (fBlockSize > fRealWidth) fBlockSize = fRealWidth;
    }
    else
    {
        if (fBlockSize > 360.0f) fBlockSize = 360.0f;
    }

    #region Bar
    if (_ProgressType == ProgressType.Bar)
    {
        // Painting inside 
        if (bDrawInner)
        {
            e.Graphics.FillRectangle(sbInner, rectInner);
        }

        // Draw a line 
        if (bDrawSurroundLine)
        {
            e.Graphics.DrawRectangle(penSurrondLine, retcSurrondLine.X, retcSurrondLine.Y, retcSurrondLine.Width, retcSurrondLine.Height);
        }

        if (_ProgressMode == ProgressMode.Known)
        {

            #region Continuous
            if (_ProgressStyle == ProgressStyle.Continuous)
            {
                // Drawing progress 
                float fProgress = Convert.ToSingle(_Value) * fRealWidth / 100;
                e.Graphics.FillRectangle(sbFore, _DrawMargin - 0.5f, fRealLeftTop, fProgress, fRealHeight);
            }
            #endregion
            #region Blocks
            else if (_ProgressStyle == ProgressStyle.Blocks)
            {
                // Get the number of blocks 
                float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                int iShowBlocks = Convert.ToInt32(fBlocks * _Value / 100);
                // Drawing progress 
                for (int i = 0; i < iShowBlocks; i++)
                {
                    e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                }
            }
            #endregion
            #region Helical
            else if (_ProgressStyle == ProgressStyle.Helical)
            {
                float fProgress = Convert.ToSingle(_Value) * fRealWidth / 100;

                // Here for a better look , Add more 1 One Block
                float fBmpWidth = fRealWidth + fBlockSize;
                float fBlocks = fBmpWidth / fBlockSize;

                Bitmap bmp = new Bitmap(Convert.ToInt32(fBmpWidth), Convert.ToInt32(fRealHeight));
                GraphicsPath gp = new GraphicsPath();
                for (int i = 0; i < fBlocks; i++)
                {
                    gp.AddPolygon(new PointF[]
                    {
                    //top-right
                    new PointF(fBmpWidth - i * fBlockSize ,0),
                    //bottom-right
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize,fRealHeight),
                    //bottom-left
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize*5/3,fRealHeight),
                    //top-left
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize*2/3,0),

                    });
                    gp.CloseFigure();
                }
                gp.CloseAllFigures();

                Graphics g = Graphics.FromImage(bmp);
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.FillPath(sbFore, gp);
                gp.Dispose();
                g.Dispose();
                e.Graphics.DrawImage(bmp, new RectangleF(fRealLeftTop, fRealLeftTop, fProgress, fRealHeight), new RectangleF(bmp.Width - fProgress - fBlockSize, 0, fProgress, bmp.Height), GraphicsUnit.Pixel);
                bmp.Dispose();
            }
            #endregion
            #region BlocksToContinuous
            else if (_ProgressStyle == ProgressStyle.BlocksToContinuous)
            {
                float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                if (_Value <= 50)
                {
                    int iShowBlocks = Convert.ToInt32(fBlocks * _Value * 2 / 100);
                    // Drawing progress 
                    for (int i = 0; i < iShowBlocks; i++)
                    {
                        e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                    }
                }
                else
                {
                    int iShowBlocks = Convert.ToInt32(fBlocks * ((_Value - 50f) * 2 / 100));
                    for (int i = iShowBlocks; i < Convert.ToInt32(fBlocks); i++)
                    {
                        e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                    }

                    // Drawing progress 
                    float fProgress = Convert.ToSingle((_Value - 50) * 2) * fRealWidth / 100;
                    e.Graphics.FillRectangle(sbFore, fRealLeftTop, fRealLeftTop, fProgress, fRealHeight);

                }
            }
            #endregion
        }
        else
        {
            #region Marquee
            if (_ProgressStyle == ProgressStyle.Marquee)
            {
                if (L_MarqueeType == MarqueeType.SlowInSlowOut)
                {
                    if (L_MarqueeStyle == MarqueeStyle.Swing)
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                        e.Graphics.FillRectangle(sbFore, Convert.ToSingle(fz) + fRealLeftTop, fRealLeftTop, fSlider, fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Cross)
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2 - fSlider;
                        float fz2 = Convert.ToSingle(fz) + fRealLeftTop;
                        float fW = fSlider;
                        if (fz2 < fRealLeftTop)
                        {
                            fW = fz2 + fSlider - (fRealLeftTop);
                            fz2 = fRealLeftTop;
                        }
                        if (fz2 + fSlider > Width - (fRealLeftTop))
                        {
                            fW = Width - (fRealLeftTop) - fz2;
                        }
                        e.Graphics.FillRectangle(sbFore, fz2, fRealLeftTop, fW, fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                        e.Graphics.FillRectangle(sbFore, fRealLeftTop, fRealLeftTop, Convert.ToSingle(fz), fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                        if (!bAcrossed)
                        {
                            e.Graphics.FillRectangle(sbFore, fRealLeftTop, fRealLeftTop, Convert.ToSingle(fz), fRealHeight);
                        }
                        else
                        {
                            e.Graphics.FillRectangle(sbFore, Convert.ToSingle(fz) + fRealLeftTop, fRealLeftTop, fRealWidth - Convert.ToSingle(fz), fRealHeight);
                        }
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Blocks)
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                        float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                        float fNowBlocks = Convert.ToSingle(fz) / fBlockSize;

                        for (int i = 0; i < fNowBlocks; i++)
                        {
                            e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                        }
                    }
                    else
                    {
                        double fz = fRange * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                        float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                        float fNowBlocks = Convert.ToSingle(fz) / fBlockSize;
                        if (!bAcrossed)
                        {
                            for (int i = 0; i < fNowBlocks; i++)
                            {
                                e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                            }
                        }
                        else
                        {
                            for (int i = Convert.ToInt32(fNowBlocks); i < fBlocks; i++)
                            {
                                e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                            }
                        }
                    }
                }
                else
                {
                    if (L_MarqueeStyle == MarqueeStyle.Swing)
                    {
                        e.Graphics.FillRectangle(sbFore, Convert.ToSingle(dMarqueeValue) + fRealLeftTop, fRealLeftTop, fSlider, fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Cross)
                    {
                        float fz2 = Convert.ToSingle(dMarqueeValue) + fRealLeftTop;
                        float fW = fSlider;
                        if (fz2 < fRealLeftTop)
                        {
                            fW = fz2 + fSlider - (fRealLeftTop);
                            fz2 = fRealLeftTop;
                        }
                        if (fz2 + fSlider > Width - (fRealLeftTop))
                        {
                            fW = Width - (fRealLeftTop) - fz2;
                        }
                        e.Graphics.FillRectangle(sbFore, fz2, fRealLeftTop, fW, fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                    {
                        e.Graphics.FillRectangle(sbFore, fRealLeftTop, fRealLeftTop, Convert.ToSingle(dMarqueeValue), fRealHeight);
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                    {
                        if (!bAcrossed)
                        {
                            e.Graphics.FillRectangle(sbFore, fRealLeftTop, fRealLeftTop, Convert.ToSingle(dMarqueeValue), fRealHeight);
                        }
                        else
                        {
                            e.Graphics.FillRectangle(sbFore, Convert.ToSingle(dMarqueeValue) + fRealLeftTop, fRealLeftTop, fRealWidth - Convert.ToSingle(dMarqueeValue), fRealHeight);
                        }
                    }
                    else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Blocks)
                    {
                        float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                        float fNowBlocks = Convert.ToSingle(dMarqueeValue) / fBlockSize;

                        for (int i = 0; i < fNowBlocks; i++)
                        {
                            e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                        }
                    }
                    else
                    {
                        float fBlocks = Convert.ToSingle(fRealWidth) / fBlockSize;
                        float fNowBlocks = Convert.ToSingle(dMarqueeValue) / fBlockSize;
                        if (!bAcrossed)
                        {
                            for (int i = 0; i < fNowBlocks; i++)
                            {
                                e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                            }
                        }
                        else
                        {
                            for (int i = Convert.ToInt32(fNowBlocks); i < fBlocks; i++)
                            {
                                e.Graphics.FillRectangle(sbFore, i * fBlockSize + fRealLeftTop, fRealLeftTop, fBlockSize * 2 / 3, fRealHeight);
                            }
                        }
                    }
                }
            }
            #endregion
            #region Helical
            else if (_ProgressStyle == ProgressStyle.Helical)
            {                        
                // Here for a better look , Add more 2 One Block
                float fBmpWidth = fRealWidth + fBlockSize*2;
                float fBlocks = fBmpWidth / fBlockSize;

                Bitmap bmp = new Bitmap(Convert.ToInt32(fBmpWidth), Convert.ToInt32(fRealHeight));
                GraphicsPath gp = new GraphicsPath();
                for (int i = 0; i < fBlocks; i++)
                {
                    gp.AddPolygon(new PointF[]
                    {
                    //top-right
                    new PointF(fBmpWidth - i * fBlockSize ,0),
                    //bottom-right
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize,fRealHeight),
                    //bottom-left
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize*5/3,fRealHeight),
                    //top-left
                    new PointF(fBmpWidth - i * fBlockSize - fBlockSize*2/3,0),

                    });
                    gp.CloseFigure();
                }
                gp.CloseAllFigures();

                Graphics g = Graphics.FromImage(bmp);
                g.SmoothingMode = SmoothingMode.HighQuality;
                g.FillPath(sbFore, gp);
                gp.Dispose();
                g.Dispose();
                e.Graphics.DrawImage(bmp, new RectangleF(fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight), new RectangleF(Convert.ToSingle(dMarqueeValue) + fBlockSize, 0, fRealWidth, bmp.Height), GraphicsUnit.Pixel);
                bmp.Dispose();
            }
            #endregion
        }
    }
    #endregion
    #region Arc
    else if (_ProgressType == ProgressType.Arc)
    {
        // Painting inside 
        if (bDrawInner)
        {
            e.Graphics.FillEllipse(sbInner, rectInner);
        }

        // Draw a line 
        if (bDrawSurroundLine)
        {
            e.Graphics.DrawEllipse(penSurrondLine, retcSurrondLine.X, retcSurrondLine.Y, retcSurrondLine.Width, retcSurrondLine.Height);
        }

        #region Continuous
        if (_ProgressStyle == ProgressStyle.Continuous)
        {
            float fProgress = Convert.ToSingle(_Value * 3.6);
            if (fProgress > 0)
            {
                e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, fProgress);
            }
        }
        #endregion
        #region Blocks
        else if (_ProgressStyle == ProgressStyle.Blocks)
        {
            // Get the number of blocks 
            float fBlocks = 360.0f / fBlockSize;
            int iShowBlocks = Convert.ToInt32(fBlocks * _Value / 100);
            // Drawing progress 
            for (int i = 0; i < iShowBlocks; i++)
            {
                // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
            }
        }
        #endregion
        #region BlocksToContinuous
        else if (_ProgressStyle == ProgressStyle.BlocksToContinuous)
        {
            // Get the number of blocks 
            float fBlocks = 360.0f / fBlockSize;
            if (_Value <= 50)
            {
                int iShowBlocks = Convert.ToInt32(fBlocks * _Value * 2 / 100);
                // Drawing progress 
                for (int i = 0; i < iShowBlocks; i++)
                {
                    // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                    // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                }
            }
            else
            {
                int iShowBlocks = Convert.ToInt32(fBlocks * (_Value - 50f) * 2 / 100);
                // Drawing progress 
                for (int i = iShowBlocks; i < Convert.ToInt32(fBlocks); i++)
                {
                    // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                    // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                }

                float fProgress = (_Value - 50f) * 2 * 3.6f;
                if (fProgress > 0)
                {
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, fProgress);
                }
            }
        }
        #endregion
        #region Marquee
        else if (_ProgressStyle == ProgressStyle.Marquee)
        {
            if (L_MarqueeType == MarqueeType.SlowInSlowOut)
            {
                if (L_MarqueeStyle == MarqueeStyle.Cross || L_MarqueeStyle == MarqueeStyle.Swing)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2 + 270 - fSlider / 2;
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, Convert.ToSingle(fz), fSlider);
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    if (!bAcrossed)
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, Convert.ToSingle(fz));
                    }
                    else
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + Convert.ToSingle(fz), Convert.ToSingle(360 - fz));
                    }
                }
                else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, Convert.ToSingle(fz));
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    float fBlocks = Convert.ToSingle(fz / fBlockSize);
                    float fAllBlocks = 360.0f / fBlockSize;
                    if (!bAcrossed)
                    {
                        for (int i = 0; i < fBlocks; i++)
                        {
                            e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                    else
                    {
                        for (float i = fAllBlocks - 1; i >= fBlocks; i--)
                        {
                            e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                }
                else
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    float fBlocks = Convert.ToSingle(fz / fBlockSize);

                    for (int i = 0; i < fBlocks; i++)
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                    }

                }

            }
            else
            {
                if (L_MarqueeStyle == MarqueeStyle.Cross || L_MarqueeStyle == MarqueeStyle.Swing)
                {
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, Convert.ToSingle(dMarqueeValue), fSlider);
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                {
                    if (!bAcrossed)
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, Convert.ToSingle(dMarqueeValue));
                    }
                    else
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + Convert.ToSingle(dMarqueeValue), Convert.ToSingle(360 - dMarqueeValue));
                    }
                }
                else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                {
                    e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270, Convert.ToSingle(dMarqueeValue));
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks)
                {
                    float fBlocks = Convert.ToSingle(dMarqueeValue / fBlockSize);
                    float fAllBlocks = 360.0f / fBlockSize;
                    if (!bAcrossed)
                    {
                        for (int i = 0; i < fBlocks; i++)
                        {
                            e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                    else
                    {
                        for (float i = fAllBlocks - 1; i >= fBlocks; i--)
                        {
                            e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                }
                else
                {
                    float fBlocks = Convert.ToSingle(dMarqueeValue / fBlockSize);
                    for (int i = 0; i < fBlocks; i++)
                    {
                        e.Graphics.DrawArc(penSurroundArc, retcSurrondArc, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                    }
                }
            }

        }
        #endregion
    }
    #endregion
    #region Pie
    else if (_ProgressType == ProgressType.Pie)
    {
        // Painting inside 
        if (bDrawInner)
        {
            e.Graphics.FillEllipse(sbInner, rectInner);
        }

        // Draw a line 
        if (bDrawSurroundLine)
        {
            e.Graphics.DrawEllipse(penSurrondLine, retcSurrondLine.X, retcSurrondLine.Y, retcSurrondLine.Width, retcSurrondLine.Height);
        }

        #region Continuous
        if (_ProgressStyle == ProgressStyle.Continuous)
        {
            // Drawing progress 
            //360/100;
            float fProgress = Convert.ToSingle(_Value * 3.6);
            if (fProgress > 0)
            {
                // If not fProgress>0 The judgment of , When the designer adjusts the size, if it is above other control elements, an exception will appear , Causes rendering to fail , Although it can still be compiled and used .
                e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, fProgress);
            }
        }
        #endregion
        #region Blocks
        else if (_ProgressStyle == ProgressStyle.Blocks)
        {
            // Get the number of blocks 
            float fBlocks = 360.0f / fBlockSize;
            int iShowBlocks = Convert.ToInt32(fBlocks * _Value / 100);
            // Drawing progress 
            for (int i = 0; i < iShowBlocks; i++)
            {
                // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
            }
        }
        #endregion
        #region 
        else if (_ProgressStyle == ProgressStyle.BlocksToContinuous)
        {
            // Get the number of blocks 
            float fBlocks = 360.0f / fBlockSize;
            if (_Value <= 50)
            {
                int iShowBlocks = Convert.ToInt32(fBlocks * _Value * 2 / 100);
                // Drawing progress 
                for (int i = 0; i < iShowBlocks; i++)
                {
                    // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                    // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                }
            }
            else
            {
                int iShowBlocks = Convert.ToInt32(fBlocks * (_Value - 50f) * 2 / 100);
                // Drawing progress 
                for (int i = iShowBlocks; i < Convert.ToInt32(fBlocks); i++)
                {
                    // For DrawArc for , It will occur in excess of 360 Degree, resulting in overlap , So judgment is needed , Simultaneous use 360-1, To prevent contact .
                    // You can optimize it later : If the distribution is not exactly 3 Multiple of , Take a similar value , So that it can be 3 to be divisible by .
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                }

                // Drawing progress 
                //360/100;
                float fProgress = (_Value - 50f) * 2 * 3.6f;
                if (fProgress > 0)
                {
                    // If not fProgress>0 The judgment of , When the designer adjusts the size, if it is above other control elements, an exception will appear , Causes rendering to fail , Although it can still be compiled and used .
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, fProgress);
                }
            }
        }
        #endregion
        #region Marquee
        else if (_ProgressStyle == ProgressStyle.Marquee)
        {
            if (L_MarqueeType == MarqueeType.SlowInSlowOut)
            {
                if (L_MarqueeStyle == MarqueeStyle.Cross || L_MarqueeStyle == MarqueeStyle.Swing)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2 + 270 - fSlider / 2;
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, Convert.ToSingle(fz), fSlider);
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    if (!bAcrossed)
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, Convert.ToSingle(fz));
                    }
                    else
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + Convert.ToSingle(fz), Convert.ToSingle(360 - fz));
                    }
                }
                else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, Convert.ToSingle(fz));
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks)
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    float fBlocks = Convert.ToSingle(fz / fBlockSize);
                    float fAllBlocks = 360.0f / fBlockSize;
                    if (!bAcrossed)
                    {
                        for (int i = 0; i < fBlocks; i++)
                        {
                            e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                    else
                    {
                        for (float i = fAllBlocks - 1; i >= fBlocks; i--)
                        {
                            e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                }
                else
                {
                    double fz = 360 * (Math.Sin((dMarqueeValue - 90) * Math.PI / 180) + 1) / 2;
                    float fBlocks = Convert.ToSingle(fz / fBlockSize);

                    for (int i = 0; i < fBlocks; i++)
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                    }

                }
            }
            else
            {
                if (L_MarqueeStyle == MarqueeStyle.Cross || L_MarqueeStyle == MarqueeStyle.Swing)
                {
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, Convert.ToSingle(dMarqueeValue), fSlider);
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                {
                    if (!bAcrossed)
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, Convert.ToSingle(dMarqueeValue));
                    }
                    else
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + Convert.ToSingle(dMarqueeValue), Convert.ToSingle(360 - dMarqueeValue));
                    }
                }
                else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
                {
                    e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270, Convert.ToSingle(dMarqueeValue));
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks)
                {
                    float fBlocks = Convert.ToSingle(dMarqueeValue / fBlockSize);
                    float fAllBlocks = 360.0f / fBlockSize;
                    if (!bAcrossed)
                    {
                        for (int i = 0; i < fBlocks; i++)
                        {
                            e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                    else
                    {
                        for (float i = fAllBlocks - 1; i >= fBlocks; i--)
                        {
                            e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                        }
                    }
                }
                else
                {
                    float fBlocks = Convert.ToSingle(dMarqueeValue / fBlockSize);
                    for (int i = 0; i < fBlocks; i++)
                    {
                        e.Graphics.FillPie(sbFore, fRealLeftTop, fRealLeftTop, fRealWidth, fRealHeight, 270 + i * fBlockSize, fBlockSize * 2 / 3 > (359.0f - i * fBlockSize) ? (359.0f - i * fBlockSize) : fBlockSize * 2 / 3);
                    }
                }
            }

        }
        #endregion
    }
    #endregion

    #region Text

    if (_ProgressText != ProgressText.None)
    {
        if (_ProgressStyle != ProgressStyle.Marquee)
        {
            string sText = _ProgressText == ProgressText.Number ? _Value.ToString() : _Value.ToString() + "%";
            SizeF sizeText = e.Graphics.MeasureString(sText, Font);
            float fx = (Width - sizeText.Width) / 2f;
            float fy = (Height - sizeText.Height) / 2f;
            e.Graphics.DrawString(sText, Font, _TextColor == Color.Empty ? sbFore : sbText, fx, fy);
        }
    }

    #endregion

    sbInner.Dispose();
    sbFore.Dispose();
    sbText.Dispose();
}
OnPaint
private void TTimer_Tick(object sender, EventArgs e)
{
    // Progress actual drawing width 、 Height 
    float fRealWidth = Width - _DrawMargin * 2;
    float fRealHeight = Height - _DrawMargin * 2;

    float fSlider = Convert.ToSingle(fRealWidth) / 5;
    if (_ProgressType != ProgressType.Bar)
    {
        //360/5
        fSlider = 72;
    }

    float fRange = 0;
    if (L_MarqueeStyle == MarqueeStyle.Swing) fRange = fRealWidth - fSlider;
    else if (L_MarqueeStyle == MarqueeStyle.Cross) fRange = fRealWidth + fSlider;
    else fRange = fRealWidth;

    double dStep = Convert.ToDouble(L_MarqueeTime) / 10;
    double dMarqueePer = 180.0 / dStep;
    if (L_MarqueeType == MarqueeType.Even)
    {
        if (_ProgressType == ProgressType.Bar)
        {
            dMarqueePer = fRange / dStep;
        }
        else
        {
            dMarqueePer = 360.0 / dStep;
        }
    }

    double dPeriod = 180;
    if (L_MarqueeStyle == MarqueeStyle.Swing || L_MarqueeStyle == MarqueeStyle.Reciprocation_Blocks || L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous) dPeriod = 360;

    if (_ProgressType == ProgressType.Bar)
    {
        if (_ProgressStyle == ProgressStyle.Marquee)
        {
            if (L_MarqueeType == MarqueeType.SlowInSlowOut)
            {
                if (dMarqueeValue > dPeriod)
                {
                    bAcrossed = !bAcrossed;
                    dMarqueeValue = 0;
                }
                dMarqueeValue += dMarqueePer;
                Invalidate();
            }
            else
            {
                if (L_MarqueeStyle == MarqueeStyle.Cross)
                {
                    bToRight = true;
                    if (dMarqueeValue > fRange) dMarqueeValue = -fSlider;
                }
                else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks || L_MarqueeStyle == MarqueeStyle.Across_Continuous)
                {
                    bToRight = true;
                    if (dMarqueeValue > fRange)
                    {
                        bAcrossed = !bAcrossed;
                        dMarqueeValue = 0;
                    }
                }
                else
                {
                    if (dMarqueeValue > fRange) bToRight = false;
                    if (dMarqueeValue < 0) bToRight = true;
                }
                dMarqueeValue = bToRight ? dMarqueeValue + dMarqueePer : dMarqueeValue - dMarqueePer;
                Invalidate();
            }
        }
        else
        {
            if (dMarqueeValue > 0) dMarqueeValue = 0;
            dMarqueeValue -= 1;
            if (dMarqueeValue <-_BlockSize) dMarqueeValue = 0;                   
            Invalidate();
        }
    }
    else if (_ProgressType == ProgressType.Arc || _ProgressType == ProgressType.Pie)
    {
        // In order to be more intuitive , namely : When you go to the top, the speed changes from the slowest to the slowest , At the bottom, speed up to the fastest , So we need to start from 270 Degree begins .
        if (L_MarqueeType == MarqueeType.SlowInSlowOut)
        {
            if (dMarqueeValue > dPeriod)
            {
                bAcrossed = !bAcrossed;
                dMarqueeValue = 0;
            }
            dMarqueeValue += dMarqueePer;
            Invalidate();
        }
        else
        {
            if (L_MarqueeStyle == MarqueeStyle.Cross)
            {
                bToRight = true;
                if (dMarqueeValue > 360) dMarqueeValue = 0;
            }
            else if (L_MarqueeStyle == MarqueeStyle.Across_Blocks || L_MarqueeStyle == MarqueeStyle.Across_Continuous)
            {
                bToRight = true;
                if (dMarqueeValue > 360)
                {
                    bAcrossed = !bAcrossed;
                    dMarqueeValue = 0;
                }
            }
            else if (L_MarqueeStyle == MarqueeStyle.Reciprocation_Blocks || L_MarqueeStyle == MarqueeStyle.Reciprocation_Continuous)
            {
                if (dMarqueeValue > 360) bToRight = false;
                if (dMarqueeValue < 0) bToRight = true;
            }
            else
            {
                if (dMarqueeValue > 270 - fSlider / 2) bToRight = false;
                if (dMarqueeValue < -90 - fSlider / 2) bToRight = true;
            }

            dMarqueeValue = bToRight ? dMarqueeValue + dMarqueePer : dMarqueeValue - dMarqueePer;
            Invalidate();
        }
    }

}
Timer_Tick

 

Draw a progress bar , In fact, it is the three components of the progress bar —— background 、 The border 、 Progress —— Draw them separately .

1, background

(1) The bar (Bar)

Fill a rectangle , The rectangular range here is the control element range minus “ Background shrink width ” After the scope of .

(2) A round cake (Pie) And the arc (Arc)

Fill a circle , The same range is the control element range minus “ Background shrink width ” After the scope of .

2, The border

(1) The bar (Bar)

Draw a rectangle , The width of the brush is the width of the border , Pay attention to the extent of the drawing , Including starting point and width and height , The width and height should be subtracted by half of the width of the border , Because when drawing brushes , It's drawing from the middle of the brush width .

(2) A round cake (Pie) And the arc (Arc)

Draw a circle , The width of the brush is the width of the border . Also pay attention to the scope of the drawing , The details are the same as above .

3, Progress

This is the most complex part of the implementation , It's not that difficult , The main thing is that there are too many effects to draw .

There are two situations in drawing progress , One is that the progress is clear , One is that the progress is not clear (Marquee Style ).

In each case , There are many styles of progress , Like continuous 、 Blocks and so on .

(1), The schedule is clear

1.1, Continuous

(1) The bar (Bar)

Fill a rectangle , Notice that the starting point of the drawing is the property “ Progress draws the edge of the fan ” Value . The width of the rectangle is the current progress value divided by 100 Multiply it by the paintable range .

In short, it's a rectangle drawn as a percentage .

(2) A round cake (Pie)

Fill a sector , In addition to drawing the starting point of the range , What needs to be noted is the starting angle . For methods FillPie for , Horizontally to the right 0 degree . And we're going up in the vertical direction , So the starting angle is 270.

ditto , The layoffs plotted are percentages : Current value /100*360.

(3) Arc (Arc)

Draw an arc , As above, we need to pay attention to the starting angle of 270. At the same time, we should also pay attention to “ Arc thickness ” This property , So when calculating the drawing range, subtract the corresponding value .

ditto , The layoffs plotted are percentages : Current value /100*360.

 

1.2, Blocks

(1) The bar (Bar)

  First calculate the current width range that can be drawn , And then divide by “ Block width ”, Figure out how many can be drawn “ Block ”, Here we need to pay attention to “ Block width ” Is included 2/3 There are color parts and 1/3 No color part ( Act as a gap ), In the previous section, we explained in detail .

And then put these in turn “ Block ” Just draw .

(2) A round cake (Pie)

  ditto , But here “ Block width ” It's an angle , Also calculate how many are needed “ Small fan ”, Then draw it in turn .

(3) Arc (Arc)

   ditto , But here “ Block width ” It's an angle , Also calculate how many are needed “ A little arc ”, Then draw it in turn .

 

1.3, Two stage formula


We can see from the above figure that , The two-part formula is to put “ Continuous ” and “ Blocks ” Together , Draw it first “ Blocks ” Draw it again “ Continuous ”.

One thing that needs to be noted here is that only 50%, So when you calculate the corresponding range, you multiply it by 2.

Because “ Continuous ” and “ Blocks ” I have talked about , I will not repeat it here .

 

1.4, screw

The spiral has only “ The bar (Bar)” To support , It itself is “ Blocks ” The deformation of , So I will use “ Block width ” This property .

It was explained in detail in the previous section , So I won't repeat it here .

 

2, The progress is not clear (Marquee Style )

Although there are many Marquee Style , But in the end, there are three categories : Position change 、 Range change 、 screw .

among ,“ screw ” It was explained in detail in the previous section , So I won't repeat it here .

No matter “ Position change ” Or “ Range change ”, It is through the timer to cycle according to the interval to change the corresponding value . and “ Uniform speed ” Effect and “ Slow motion ” The effect is whether the values change at each interval .

As for uniform speed and slow motion, I have discussed in detail in my previous articles , No more details here .

 

(1) Position change

 

Through the pictures above , At a glance , Position change , For the bars (Bar) for , It's changing the starting position ; For round cakes (Pie) And the arc (Arc) for , It's about changing the starting angle .

  

(2) Range change

Through the pictures above , At a glance , Range change , For the bars (Bar) for , Is to change the drawing range , To be precise, it's a change in width ; For round cakes (Pie) And the arc (Arc) for , It's the change of the drawing angle .

 

(3) The location and the range have changed

 

 

Through the pictures above , At a glance , It belongs to the combination of the former two .

 

 ( Four ) Other instructions

In implementation , I didn't limit the pancakes (Pie) And the arc (Arc) It has to be a circle , In other words, the width and height must be equal .

Because this can achieve some more interesting effect , as follows :

 


 

5、 ... and 、 Effect demonstration

In order to better show the characteristics of the progress bar , So let's build a demo program like this .

 

 

Most of the pictures and moving pictures in this paper are recorded with this demo program .

The specific demo program and source code project are downloaded at the end of the paper , Please download and experience automatically .

 


 

  6、 ... and 、 Conclusion

We will find that Marquee Style animation and our common loading (Loading) The animation is a little bit like , Actually , The realization of loading animation is just the realization in this paper Marquee The way the style is used , So we'll do it later “ Load (Loading) Control element ”.

 

This article is just a way to attract the jade , Readers should not be limited by my ideas , You can do what you want .

 

The technology is not advanced or backward , Only suitable and not suitable .

therefore , Have more confidence in your knowledge , Let go of your imagination , And improve yourself in practice .

 


 

7、 ... and 、 Source code and project download

https://files.cnblogs.com/files/lesliexin/04,LProgressBar.7z

 

版权声明
本文为[itread01]所创,转载请带上原文链接,感谢