倒置垂直进度条

本文关键字:垂直 | 更新日期: 2023-09-27 18:04:51

我想做一个垂直进度条,所以我发现了这个:垂直进度条

但是现在如果你有水平进度条你可以让它从左到右/右到左工作所以我想让我的垂直进度条从上到下工作而不是像现在这样从下到下工作。

有可能吗?

我的代码

public class VerticalProgressBar : ProgressBar
{
    protected override CreateParams CreateParams
    {
        get
        {
            CreateParams cp = base.CreateParams;
            cp.Style |= 0x04;
            return cp;
        }
    }
}

我使用的是c# .NET 3.5 Windows Forms

倒置垂直进度条

支持视觉样式的代码包含一些bug。这段代码:

 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);
        }
    }

似乎没有任何CreateParams支持倒垂直ProgressBar。这些是来自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

我尝试改变rightolleft的值,但无济于事。似乎也没有办法任意旋转Windows窗体控件。

一个可能的解决方案可能是使用WPF的进度条。你可以把它旋转90度,它应该是你想要的。另一个选择是使用第三方Progressbar控件或创建一个自定义呈现控件。呈现一个简单的平面进度条应该是相当容易的。

你必须像这样重写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);
    }
}

现在你可以用同样的方式使用它你链接的垂直进度条和LeftToRight/righttolleft功能将模仿正常的进度条(关于进度绘制方向)。

我注意到上面的代码不能很好地处理视觉样式。下面是垂直进度条的改进版本,它应该覆盖视觉样式:

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);
    }
}

我必须为自下而上的进度条绘制单独的块,因为我想保持其他进度条的外观和感觉。否则,该条会看起来是从中间绘制的。