颠倒的垂直进度条?
Posted
技术标签:
【中文标题】颠倒的垂直进度条?【英文标题】:Upsidedown Vertical Progress Bar? 【发布时间】:2011-10-23 08:42:24 【问题描述】:我想做一个垂直进度条,所以我发现了这个: Vertical progress bar
但是现在,如果你有水平进度条,你可以让它从 LeftToRight / RightToLeft 工作,所以我希望我的垂直进度条从 UpToDown 工作,而不是像现在这样从 DownToUp 工作..
有可能吗?
这是我的代码
public class VerticalProgressBar : ProgressBar
protected override CreateParams CreateParams
get
CreateParams cp = base.CreateParams;
cp.Style |= 0x04;
return cp;
我正在使用 C# .NET 3.5 Windows 窗体
【问题讨论】:
WPF?银光?窗体? ASP? 您需要自己绘制,而不是使用标准控件。我可以为这样的应用推荐 WPF。cp.Style |= 0x04;
?真的??我很高兴我跳过了 winforms 并直接进入了 WPF。
【参考方案1】:
支持视觉样式的代码包含一些错误。这段代码:
ProgressBarRenderer.DrawVerticalBar(e.Graphics, e.ClipRectangle);
必须用这个替换:
ProgressBarRenderer.DrawVerticalBar(e.Graphics, ClientRectangle);
并且我重新发布了没有此错误的完整源代码:
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);
【讨论】:
【参考方案2】:似乎没有任何支持倒置垂直 ProgressBar 的 CreateParams。这些是来自 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
我尝试更改 RightToLeft 值无济于事。似乎也没有办法任意旋转 Windows 窗体控件。
可能的解决方案是使用 WPF ProgressBar。您可以将其旋转 90 度,它应该可以满足您的需求。另一种选择是使用第三方 Progressbar 控件或创建自定义呈现的控件。渲染一个简单的平面进度条应该相当容易。
【讨论】:
我可以旋转 Windows 窗体控件吗? 不,您不能旋转控件本身。但是,您可以覆盖 Paint() 方法并旋转内容,但在您的情况下这无济于事。如果您不想要 WPF 开销,您可以在 CodeProject 找到大量自定义进度条控件。您至少可以将其中一个用作自定义控件的起点。 我可以只添加 WPF 库吗?或者我需要为此创建一个新的 WPF 项目?如果我只能添加库,你能给我举个例子吗?我是 WPF 新手。 这篇博文是一个好的开始:nayyeri.net/host-wpf-controls-in-windows-forms 基本上你可以使用ElementHost Windows 窗体控件。还有一个关于 WPF 和 Winforms 互操作性的 Microsoft 页面可能对您有所帮助:msdn.microsoft.com/en-us/library/ms751797.aspx【参考方案3】:您必须像这样覆盖 OnPaint():
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);
现在您可以像使用它一样使用它了 Vertical progress bar 您已链接,LeftToRight / RightToLeft 功能将模仿普通 ProgressBar 的功能(关于进度绘图方向)。
【讨论】:
【参考方案4】:我注意到上面的代码不适用于视觉样式。这是一个改进版的垂直进度条,应该涵盖视觉样式:
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);
我必须为自下而上的进度条绘制单独的块,因为我想保持其他进度条的外观和感觉。否则,该条似乎是从中间绘制的。
【讨论】:
以上是关于颠倒的垂直进度条?的主要内容,如果未能解决你的问题,请参考以下文章
QT软件开发之基础控件--2.5.2 QProgressBar进度条