颠倒的垂直进度条?

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

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

【讨论】:

以上是关于颠倒的垂直进度条?的主要内容,如果未能解决你的问题,请参考以下文章

进度条摆动效果

自定义垂直拖动的seekbar进度条

Android自定义View实现可拖拽的进度条

QT软件开发之基础控件--2.5.2 QProgressBar进度条

PyQt5-Qt DesignerQProgressBar() 进度条

IOS Swift中进度条和标签的约束