代码之家  ›  专栏  ›  技术社区  ›  Svish

C:覆盖progressbar上的paint不起作用?

  •  6
  • Svish  · 技术社区  · 16 年前

    在想应该很容易创建一个 ProgressBar 这给自己画了一些文字。但是,我不太确定这里发生了什么…

    我添加了以下两个覆盖:

        protected override void OnPaintBackground(PaintEventArgs pevent)
        {
            base.OnPaintBackground(pevent);
            var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis;
            TextRenderer.DrawText(pevent.Graphics, "Hello", Font, Bounds, Color.Black, flags);
        }
    
        protected override void OnPaint(PaintEventArgs e)
        {
            base.OnPaint(e);
            var flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis;
            TextRenderer.DrawText(e.Graphics, "Hello", Font, Bounds, Color.Black, flags);
        }
    

    但是,我没有得到文本,而且方法似乎也没有被调用。这是怎么回事?


    更新: 多亏了迄今为止的两个答案,我才真正把它叫做 OnPaint 通过使用 SetStyle(ControlStyles.UserPaint, true) 我已经让它通过发送 new Rectangle(0, 0, Width, Height) 而不是 Bounds .

    我现在确实收到了短信,但是 进度条 不见了…重点是把文本放在 进度条 . 我知道怎么解决这个问题吗?

    5 回复  |  直到 15 年前
        1
  •  1
  •   MusiGenesis    16 年前

    你的问题是你在传球 Bounds 作为矩形参数。bounds包含控件的高度和宽度,这是您想要的,但它也包含控件相对于父窗体的左上角属性,因此“hello”在控件上的偏移量与控件在其父窗体上的偏移量相同。

    替换 界限 具有 new Rectangle(0, 0, this.Width, this.Height) 你应该看到你的“你好”。

        2
  •  12
  •   Christian Westman    15 年前

    您可以重写wndproc并捕获wmpaint消息。

    下面的示例在其中心绘制ProgressBar的文本属性。

    public class StatusProgressBar : ProgressBar
    {
        const int WmPaint = 15;
    
        protected override void WndProc(ref Message m)
        {
            base.WndProc(ref m);
    
            switch (m.Msg)
            {
                case WmPaint:
                    using (var graphics = Graphics.FromHwnd(Handle))
                    {
                        var textSize = graphics.MeasureString(Text, Font);
    
                        using(var textBrush = new SolidBrush(ForeColor))
                            graphics.DrawString(Text, Font, textBrush, (Width / 2) - (textSize.Width / 2), (Height / 2) - (textSize.Height / 2));
                    }
                    break;
            }
        }
    }
    
        3
  •  6
  •   Ed Swangren    15 年前

    我需要自己做这个,我想我会发布一个简化的解决方案示例,因为我找不到任何示例。实际上,如果使用ProgressBanderer类,这非常简单:

    class MyProgressBar : ProgressBar
    {
        public MyProgressBar()
        {
            this.SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true);
        }
    
        protected override void OnPaint(PaintEventArgs e)
        {
            Rectangle rect = this.ClientRectangle;
            Graphics g = e.Graphics;
    
            ProgressBarRenderer.DrawHorizontalBar( g, rect );
            rect.Inflate(-3, -3);
            if ( this.Value > 0 )
            {
                Rectangle clip = new Rectangle( rect.X, rect.Y, ( int )Math.Round( ( ( float )this.Value / this.Maximum ) * rect.Width ), rect.Height );
                ProgressBarRenderer.DrawHorizontalChunks(g, clip);
            }
    
            // assumes this.Maximum == 100
            string text = this.Value.ToString( ) + '%';
    
            using ( Font f = new Font( FontFamily.GenericMonospace, 10 ) )
            {
                SizeF strLen = g.MeasureString( text, f );
                Point location = new Point( ( int )( ( rect.Width / 2 ) - ( strLen.Width / 2 ) ), ( int )( ( rect.Height / 2 ) - ( strLen.Height / 2 ) ) );
                g.DrawString( text, f, Brushes.Black, location ); 
            }
        }
    }
    
        4
  •  1
  •   Maciek Talaska    16 年前

    似乎如果调用“setStyle(controlStyles.userpaint,true)”,则无法调用为ProgressBar实现的标准onpaint方法(使用base.onpaint(e)根本不起作用)。最奇怪的是,即使你真的创建了一个用户控件,并试图在进度条上绘制一些文本…它似乎不太管用…当然,你可以在上面贴个标签…但我想这并不是你想要实现的。

    好吧,看来我已经设法解决了这个问题。虽然有点复杂。首先,您需要创建一个透明的标签控件。代码如下:

    public class TransparentLabel : System.Windows.Forms.Label
    {
        public TransparentLabel()
        {
            this.SetStyle(ControlStyles.Opaque, true);
            this.SetStyle(ControlStyles.OptimizedDoubleBuffer, false);
        }
    
        protected override CreateParams CreateParams
        {
            get
            {
                CreateParams cp = base.CreateParams;
                cp.ExStyle |= 0x20;
                return cp;
            }
        }
    }
    

    第二件事是创建用户控件,在它上面放置一个ProgressBar(dock=fill)-这将是我们将使用的控件,而不是标准的ProgressBar。代码:

    public partial class UserControl2 : UserControl
    {
        public UserControl2()
        {
            InitializeComponent();
        }
    
        protected override void OnPaint(PaintEventArgs e)
        {
            this.progressBar1.SendToBack();
            this.transparentLabel1.BringToFront();
            this.transparentLabel1.Text = this.progressBar1.Value.ToString();
            this.transparentLabel1.Invalidate();
       }
    
        public int Value
        {
            get { return this.progressBar1.Value; }
            set
            {
                this.progressBar1.Value = value; 
            }
        }
    }
    

    ProgressBar的奇怪之处在于它“透支”了放置在它上面的控件,因此需要将ProgressBar向后发送,并将Label控件置于前面。目前我还没有找到更优雅的解决方案。 这样就可以了,标签显示在进度条上,标签控件的背景是透明的,所以我认为它看起来像是您想要的那样:)

    如果你愿意,我可以分享我的示例代码…

    噢,顺便说一句,我刚才提到的ProgressBar控件的这种奇怪的行为导致了无法使用图形对象在从ProgressBar派生的控件上绘制任何内容。实际正在绘制文本(或使用图形对象绘制的任何内容),但…在ProgressBar控件的后面(如果仔细观察,您可能会看到当ProgressBar的值改变时,用户绘制的东西会闪烁,需要重新绘制自己)。

        5
  •  0
  •   Patratacus    15 年前

    这是另一个解决方案以及其他人的建议。我对ProgressBar控件进行了子类化以使其工作。我混合和匹配了来自不同地方的代码。绘画活动可能更干净,但这是你的事;)

       public class LabeledProgressBar: ProgressBar
       {
          private string labelText;
    
          public string LabelText
          {
             get { return labelText; }
             set { labelText = value; }
          }
    
          public LabeledProgressBar() : base()
          { 
             this.SetStyle(ControlStyles.UserPaint, true);
             this.SetStyle(ControlStyles.AllPaintingInWmPaint, true);
    
             this.Paint += OnLabelPaint;
          }
    
          public void OnLabelPaint(object sender, PaintEventArgs e)
          {
             using(Graphics gr = this.CreateGraphics())
            {
             string str = LabelText + string.Format(": {0}%", this.Value);
             LinearGradientBrush brBG = new LinearGradientBrush(e.ClipRectangle, 
                 Color.GreenYellow, Color.Green, LinearGradientMode.Horizontal);
             e.Graphics.FillRectangle(brBG, e.ClipRectangle.X, e.ClipRectangle.Y, 
                 e.ClipRectangle.Width * this.Value / this.Maximum, e.ClipRectangle.Height);
             e.Graphics.DrawString(str, SystemFonts.DefaultFont,Brushes.Black,  
                new PointF(this.Width / 2 - (gr.MeasureString(str, SystemFonts.DefaultFont).Width / 2.0F),
                this.Height / 2 - (gr.MeasureString(str, SystemFonts.DefaultFont).Height / 2.0F)));
             }
           }
        }
    
    推荐文章