【问题标题】: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。

标签: c# winforms .net-3.5 components progress-bar


【解决方案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);
          }
      }
      

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

      【讨论】:

        猜你喜欢
        • 2010-11-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-21
        • 2014-03-31
        • 1970-01-01
        相关资源
        最近更新 更多