当前位置:网站首页>[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(); }
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(); } } }
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]所创,转载请带上原文链接,感谢
边栏推荐
- Named entity recognition in natural language processing: tanford core LP ner (1)
- ES6学习笔记(四):教你轻松搞懂ES6的新增语法
- Linked blocking Queue Analysis of blocking queue
- I'm afraid that the spread sequence calculation of arbitrage strategy is not as simple as you think
- 6.6.1 localeresolver internationalization parser (1) (in-depth analysis of SSM and project practice)
- Wow, elasticsearch multi field weight sorting can play like this
- A course on word embedding
- git rebase的時候捅婁子了,怎麼辦?線上等……
- Our best practices for writing react components
- Classical dynamic programming: complete knapsack problem
猜你喜欢
Who says cat can't do link tracking? Stand up for me
01. SSH Remote terminal and websocket of go language
NLP model Bert: from introduction to mastery (2)
每个前端工程师都应该懂的前端性能优化总结:
Natural language processing - BM25 commonly used in search
前端工程师需要懂的前端面试题(c s s方面)总结(二)
TensorFlow中的Tensor是什么?
How to encapsulate distributed locks more elegantly
一篇文章带你了解SVG 渐变知识
Just now, I popularized two unique skills of login to Xuemei
随机推荐
Solve the problem of database insert data garbled in PL / SQL developer
Cglib 如何实现多重代理?
ES6学习笔记(四):教你轻松搞懂ES6的新增语法
React design pattern: in depth understanding of react & Redux principle
Summary of common algorithms of linked list
Introduction to X Window System
I've been rejected by the product manager. Why don't you know
Advanced Vue component pattern (3)
The difference between gbdt and XGB, and the mathematical derivation of gradient descent method and Newton method
一篇文章带你了解CSS3圆角知识
Natural language processing - wrong word recognition (based on Python) kenlm, pycorrector
What to do if you are squeezed by old programmers? I don't want to quit
Linked blocking Queue Analysis of blocking queue
Network security engineer Demo: the original * * is to get your computer administrator rights! 【***】
It is really necessary to build a distributed ID generation service
Using NLP and ml to extract and construct web data
What is the difference between data scientists and machine learning engineers? - kdnuggets
Analysis of ThreadLocal principle
Face to face Manual Chapter 16: explanation and implementation of fair lock of code peasant association lock and reentrantlock
Unity性能优化整理