开发者

Upsidedown Vertical Progress Bar?

开发者 https://www.devze.com 2023-03-27 08:41 出处:网络
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 Vertic

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号