|
||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||
|
Announcements
Chapters
Services
Feature Zones
|
ContentsIntroductionThis was supposed to be a short article on the progress bar I wrote but it rapidly turned into an essay. The stuff in this article isn't necessary to understand the code so don't feel you have to read it. Oh, and before I forget I'm going to apologize in advance for my coding style. I've never actually had a professional (or anyone at all) really look at anything I've done before, so the way I code might be really bad. I made a Smooth ProgressBar control in VB.NET about 7 months ago as a personal project to help further my knowledge in the GDI+. Since then I upgraded my computer to Vista and immediately decided that the new progress bar was better than mine. Not wanting to waste my original effort I decided to recreate the Windows Vista Progress Bar with some added features. I've always been annoyed at the lack of a colour property in the Windows Progress Bar controls from 2000, to Vista so that was the main reason for this control. From Photoshop...For me, the first step was figuring out how the progress bar was actually drawn. Already having experience with Photoshop, I thought I'd use Photoshop to create a similar effect and then translate the stages into code using the GDI+. If you don't use Photoshop or aren't quite comfortable with using it you can skip this section and just take my word for it as it isn't very easy to follow. The first thing I did was to find a decent screenshot of the Vista progress bar. This was the best one I found. It's taken from a short article written by Daniel Moth and can be found here.
From this I broke it down visually into separate layers.
... To GDI+After learning how the progress bar could be made, the next step was to translate these steps into the GDI+. I found the easiest way to do this was to break it down into different procedures that represent the different layers. That way if I wanted to tweak one of the layers, I'd just have to comment out the bits I wanted to hide. By the end my paint event looked like this: private void ProgressBar_Paint(object sender, PaintEventArgs e)
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
DrawBackground(e.Graphics);
DrawBackgroundShadows(e.Graphics);
DrawBar(e.Graphics);
DrawBarShadows(e.Graphics);
DrawHighlight(e.Graphics);
DrawInnerStroke(e.Graphics);
DrawGlow(e.Graphics);
DrawOuterStroke(e.Graphics);
}
The first two lines make the graphics object draw with a higher quality and the other lines represent the different layers. It might not be the most efficient way of doing things CPU-wise but it makes things a lot easier for the little adjustments you have to make to get things to look right. I'll only take a brief look at each of these procedures because the code itself is fully commented and has XML documentation with it (see C__Documentation_Proess.asp for more details). In this article I quite frequently mention colours, I happen to neglect the alpha value quite a lot so if I say black I probably mean some kind of semi-transparent gray. private void DrawBackground(Graphics g)
{
Rectangle r = this.ClientRectangle; r.Width--; r.Height--;
GraphicsPath rr = RoundRect(r, 2, 2, 2, 2);
g.FillPath(new SolidBrush(this.BackgroundColor), rr);
}
The only notable thing in the private void DrawBackgroundShadows(Graphics g)
{
Rectangle lr = new Rectangle(2, 2, 10, this.Height - 5);
LinearGradientBrush lg = new LinearGradientBrush
(lr, Color.FromArgb(30, 0, 0, 0),
Color.Transparent,
LinearGradientMode.Horizontal);
lr.X--;
g.FillRectangle(lg, lr);
Rectangle rr = new Rectangle(this.Width - 12, 2, 10, this.Height - 5);
LinearGradientBrush rg = new LinearGradientBrush(rr, Color.Transparent,
Color.FromArgb(20, 0, 0, 0),
LinearGradientMode.Horizontal);
g.FillRectangle(rg, rr);
}
This method creates two 10 pixel wide rectangles and fills them with a linear gradient that goes from a low opacity black to transparent making sure that each rectangle has the darker colour on the outside. private void DrawBar(Graphics g)
{
Rectangle r = new Rectangle(1, 2, this.Width - 3, this.Height - 3);
r.Width = (int)(Value * 1.0F / (MaxValue - MinValue) * this.Width);
g.FillRectangle(new SolidBrush(GetIntermediateColor()), r);
}
The code here is pretty much the same as the code that draws the background but with two minor differences. The first is that it uses a normal rectangle as opposed to a rounded one and the second is that it uses the private void DrawBarShadows(Graphics g)
{
Rectangle lr = new Rectangle(1, 2, 15, this.Height - 3);
LinearGradientBrush lg = new LinearGradientBrush
(lr, Color.White, Color.White,
LinearGradientMode.Horizontal);
ColorBlend lc = new ColorBlend(3);
lc.Colors = new Color[]
{Color.Transparent, Color.FromArgb(40, 0, 0, 0), Color.Transparent};
lc.Positions = new float[] {0.0F, 0.2F, 1.0F};
lg.InterpolationColors = lc;
lr.X--;
g.FillRectangle(lg, lr);
Rectangle rr = new Rectangle(this.Width - 3, 2, 15, this.Height - 3);
rr.X = (int)(Value * 1.0F / (MaxValue - MinValue) * this.Width) - 14;
LinearGradientBrush rg =
new LinearGradientBrush(rr, Color.Black,Color.Black,
LinearGradientMode.Horizontal);
ColorBlend rc = new ColorBlend(3);
rc.Colors = new Color[]
{Color.Transparent, Color.FromArgb(40, 0, 0, 0), Color.Transparent};
rc.Positions = new float[] {0.0F, 0.8F, 1.0F};
rg.InterpolationColors = rc;
g.FillRectangle(rg, rr);
}
This code is almost the same as the shadows for the background except these ones are larger. They also use a different gradient. It starts off transparent and gets a bit darker before it goes completely transparent. I did this because in the Vista progress bar it doesn't just go straight from black to transparent. private void DrawHighlight(Graphics g)
{
Rectangle tr = new Rectangle(1, 1, this.Width - 1, 6);
GraphicsPath tp = RoundRect(tr, 2, 2, 0, 0);
g.SetClip(tp);
LinearGradientBrush tg = new LinearGradientBrush(tr, Color.White,
Color.FromArgb(128, Color.White),
LinearGradientMode.Vertical);
g.FillPath(tg, tp);
g.ResetClip();
Rectangle br = new Rectangle(1, this.Height - 8, this.Width - 1, 6);
GraphicsPath bp = RoundRect(br, 0, 0, 2, 2);
g.SetClip(bp);
LinearGradientBrush bg = new LinearGradientBrush(br, Color.Transparent,
Color.FromArgb(100, this.HighlightColor),
LinearGradientMode.Vertical);
g.FillPath(bg, bp);
g.ResetClip();
}
This procedure simply adds the low opacity white highlight at the top of the bar and the more transparent one at the bottom, again just some simple linear gradient drawing. private void DrawInnerStroke(Graphics g)
{
Rectangle r = this.ClientRectangle;
r.X++; r.Y++; r.Width-=3; r.Height-=3;
GraphicsPath rr = RoundRect(r, 2, 2, 2, 2);
g.DrawPath(new Pen(Color.FromArgb(100, Color.White)), rr);
}
This bit draws the low opacity line on the inside of the border. It's not overly noticeable but it still helps to add that little flare. private void DrawGlow(Graphics g)
{
Rectangle r = new Rectangle(mGlowPosition, 0, 60, this.Height);
LinearGradientBrush lgb = new LinearGradientBrush
(r, Color.White, Color.White,
LinearGradientMode.Horizontal);
ColorBlend cb = new ColorBlend(4);
cb.Colors = new Color[]
{Color.Transparent, this.GlowColor, this.GlowColor, Color.Transparent};
cb.Positions = new float[] {0.0F, 0.5F, 0.6F, 1.0F};
lgb.InterpolationColors = cb;
Rectangle clip = new Rectangle(1, 2, this.Width - 3, this.Height - 3);
clip.Width = (int)(Value * 1.0F / (MaxValue - MinValue) * this.Width);
g.SetClip(clip);
g.FillRectangle(lgb,r);
g.ResetClip();
}
This part draws the animated glow that goes across the bar. It just draws a linear gradient that draws it's X value from a private variable called private void DrawOuterStroke(Graphics g)
{
Rectangle r = this.ClientRectangle; r.Width--; r.Height--;
GraphicsPath rr = RoundRect(r, 2, 2, 2, 2);
g.DrawPath(new Pen(Color.FromArgb(178, 178, 178)), rr);
}
Same as the inner stroke but bigger. Using the code
Setting the properties is pretty easy too. The other properties are purely aesthetic and consist of the Future DevelopmentThis bit is pretty much up to you guys, if anyone makes any valid suggestions, I'd be more than happy to implement them. History
|
|||||||||||||||||||||||||||||||||||||||||