Upsidedown Vertical Progress Bar?
I wanted to do a Vertical Progress Bar so i found this: Vertical progress bar
But now like if you have Horizitonal Progress Bar you can make it work from LeftToRight / RightToLeft so i want my Vertical one to Work from UpToDown and not from DownToUp like it works now..
Is it possible?
Here is 开发者_如何学Pythonmy code
public class VerticalProgressBar : ProgressBar
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= 0x04;
return cp;
}
}
}
I'm using C# .NET 3.5 Windows Forms
Code, that support visual styles contains some bug. This code:
ProgressBarRenderer.DrawVerticalBar(e.Graphics, e.ClipRectangle);
must be replaced with this one:
ProgressBarRenderer.DrawVerticalBar(e.Graphics, ClientRectangle);
And i repost full source code without this bug:
public class VerticalProgressBar : ProgressBar
{
protected override CreateParams CreateParams
{
get
{
// Avoid CA2122
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
CreateParams cp = base.CreateParams;
cp.Style |= 0x04;
return cp;
}
}
public VerticalProgressBar()
{
// Enable OnPaint overriding
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (ProgressBarRenderer.IsSupported)
{
ProgressBarRenderer.DrawVerticalBar(e.Graphics, ClientRectangle);
const int HORIZ_OFFSET = 3;
const int VERT_OFFSET = 2;
if (this.Minimum == this.Maximum || (this.Value - Minimum) == 0 ||
this.Height < 2 * VERT_OFFSET || this.Width < 2 * VERT_OFFSET)
return;
int barHeight = (this.Value - this.Minimum) * this.Height / (this.Maximum - this.Minimum);
barHeight = Math.Min(barHeight, this.Height - 2 * VERT_OFFSET);
int barWidth = this.Width - 2 * HORIZ_OFFSET;
if (this.RightToLeftLayout && this.RightToLeft == System.Windows.Forms.RightToLeft.No)
{
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, VERT_OFFSET, barWidth, barHeight));
}
else
{
int blockHeight = 10;
int wholeBarHeight = Convert.ToInt32(barHeight / blockHeight) * blockHeight;
int wholeBarY = this.Height - wholeBarHeight - VERT_OFFSET;
int restBarHeight = barHeight % blockHeight;
int restBarY = this.Height - barHeight - VERT_OFFSET;
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, wholeBarY, barWidth, wholeBarHeight));
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, restBarY, barWidth, restBarHeight));
}
}
base.OnPaint(e);
}
}
There doesn't seem to be any CreateParams that support inverted vertical ProgressBar. These are the style parameters from the Windows API:
#define PBS_SMOOTH 0x01
#define PBS_VERTICAL 0x04
#define PBS_MARQUEE 0x08
#define PBS_SMOOTHREVERSE 0x10
#define PBST_NORMAL 1
#define PBST_ERROR 2
#define PBST_PAUSED 3
I tried changing the RightToLeft values to no avail. There also doesn't seem to be a way to arbitrarily rotate a Windows Forms control.
A possible solution may be to use the WPF ProgressBar. You could rotate it 90 degrees and it should do what you're looking for. Another option is to use a third party Progressbar control or create a custom rendered one. It should be fairly easy to render a simple flat progressbar.
You have to override OnPaint() like this:
public class VerticalProgressBar : ProgressBar
{
protected override CreateParams CreateParams
{
get
{
CreateParams cp = base.CreateParams;
cp.Style |= 0x04;
return cp;
}
}
public VerticalProgressBar()
{
// Enable OnPaint overriding
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
Graphics dc = e.Graphics;
if (this.Minimum == this.Maximum || (this.Value - Minimum) == 0)
return;
int width = this.Width; // The bar width
int height = (this.Value - this.Minimum) * this.Height / (this.Maximum - this.Minimum); // The bar height
int x = 2; // The bottom-left x pos of the bar (or upper left on upsidedown bar)
int y = this.Height - 1; // The bottom-left y pos of the bar (or upper left on upsidedown bar)
int blockheight = width * 3 / 4; // The height of the block
if (this.RightToLeftLayout && this.RightToLeft == System.Windows.Forms.RightToLeft.No)
for (int currentpos = 0; currentpos < height; currentpos += blockheight + 1)
dc.FillRectangle(new SolidBrush(this.ForeColor), x, currentpos, width, blockheight);
else
for (int currentpos = y; currentpos > y - height; currentpos -= blockheight + 1)
dc.FillRectangle(new SolidBrush(this.ForeColor), x, currentpos - blockheight, width, blockheight);
base.OnPaint(e);
}
}
Now you can use it in the same way as Vertical progress bar you linked and LeftToRight / RightToLeft functionality will mimic the one from normal ProgressBar (regarding progress drawing orientation).
I noticed the code above does not work well with visual styles. Here is an improved version of vertical progress bar that should cover visual styles:
public class VerticalProgressBar : ProgressBar
{
protected override CreateParams CreateParams
{
get
{
// Avoid CA2122
new SecurityPermission(SecurityPermissionFlag.UnmanagedCode).Demand();
CreateParams cp = base.CreateParams;
cp.Style |= 0x04;
return cp;
}
}
public VerticalProgressBar()
{
// Enable OnPaint overriding
this.SetStyle(ControlStyles.UserPaint, true);
}
protected override void OnPaint(System.Windows.Forms.PaintEventArgs e)
{
if (ProgressBarRenderer.IsSupported)
{
ProgressBarRenderer.DrawVerticalBar(e.Graphics, e.ClipRectangle);
const int HORIZ_OFFSET = 3;
const int VERT_OFFSET = 2;
if (this.Minimum == this.Maximum || (this.Value - Minimum) == 0 ||
this.Height < 2 * VERT_OFFSET || this.Width < 2 * VERT_OFFSET)
return;
int barHeight = (this.Value - this.Minimum) * this.Height / (this.Maximum - this.Minimum);
barHeight = Math.Min(barHeight, this.Height - 2 * VERT_OFFSET);
int barWidth = this.Width - 2 * HORIZ_OFFSET;
if (this.RightToLeftLayout && this.RightToLeft == System.Windows.Forms.RightToLeft.No)
{
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, VERT_OFFSET, barWidth, barHeight));
}
else
{
int blockHeight = 10;
int wholeBarHeight = Convert.ToInt32(barHeight / blockHeight) * blockHeight;
int wholeBarY = this.Height - wholeBarHeight - VERT_OFFSET;
int restBarHeight = barHeight % blockHeight;
int restBarY = this.Height - barHeight - VERT_OFFSET;
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, wholeBarY, barWidth, wholeBarHeight));
ProgressBarRenderer.DrawVerticalChunks(e.Graphics,
new Rectangle(HORIZ_OFFSET, restBarY, barWidth, restBarHeight));
}
}
base.OnPaint(e);
}
}
I had to draw separate chunks for bottom-up progress bar because I wanted to keep look and feel of other progress bars. Otherwise the bar would have appeared to be drawn from the middle.
精彩评论