2009-10-04 17 views
5

Estaba pensando que debería ser bastante fácil crear un ProgressBar que dibujara un texto sobre sí mismo. Sin embargo, no estoy muy seguro de lo que está sucediendo aquí ...C#: Anulación de OnPaint en ProgressBar no funciona?

que añaden los siguientes dos sustituciones:

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

Sin embargo, yo no recibo ningún texto, y los métodos ni siquiera parece ser llamado . ¿Que esta pasando aqui?


Actualización: Gracias a las dos respuestas hasta ahora, han conseguido que en realidad llamar a la OnPaint utilizando , y han conseguido que dibujar el texto en el lugar correcto mediante el envío de new Rectangle(0, 0, Width, Height) vez de Bounds.

Obtengo texto ahora, pero el ProgressBar se ha ido ... y el punto era como tener el texto encima del ProgressBar. ¿Alguna idea de cómo puedo resolver esto?

Respuesta

1

Tu problema es que estás pasando Bounds como tu parámetro Rectangle. Bounds contiene la altura y el ancho de su control, que es lo que quiere, pero también contiene las propiedades Superior e Izquierda de su control, en relación con el formulario principal, por lo que su "Hola" está siendo compensado en el control por mucho que el control se compensa en su forma principal.

Reemplace Bounds con new Rectangle(0, 0, this.Width, this.Height) y debería ver su "Hola".

+0

Oooh. Buena atrapada. – Svish

1

Parece que si llama a 'SetStyle (ControlStyles.UserPaint, true)' el método OnPaint estándar implementado para ProgressBar no se pudo invocar (utilizando base.OnPaint (e) no funciona en absoluto). Lo más extraño es que, incluso si realmente creas un UserControl, y tratas de dibujar algo de texto en la barra de progreso ... no parece funcionar demasiado ... Por supuesto, puedes colocar una etiqueta encima. ... pero supongo que no es realmente lo que querías lograr.

Ok, parece que he logrado resolver este problema. Aunque es un poco complicado. Primero necesita crear un control de etiqueta transparente. Código de abajo:

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

Lo segundo es la creación de control de usuario, colocar un ProgressBar en él (Muelle = Fill) - este será el control que vamos a utilizar en lugar de ProgressBar estándar. Código:

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

Lo extraño con ProgressBar es que es un sobregiro 'los controles que están siendo colocados sobre ella, por lo que se necesita para enviar progressbar con espalda, y llevar el control de etiqueta al frente. No he encontrado una solución más elegante en este momento. Esto funciona, la etiqueta se muestra en la barra de progreso, el fondo del control de etiqueta es transparente, así que creo que parece que quería que se vea :)

Puedo compartir mi código de muestra si lo desea ..

Oh, btw. este extraño comportamiento del control ProgressBar que he mencionado, es responsable de que no sea posible utilizar el objeto Graphics para extraer nada en un control que se deriva de ProgressBar. El texto (o lo que sea que dibuje utilizando el objeto Graphics) se está dibujando pero ... detrás del control ProgressBar (si lo observa más de cerca, puede ver a este usuario parpadeando cuando el valor del ProgressBar cambia y necesita volver a pintar).

+0

Bueno, en realidad es lo que quiero lograr. El problema es que cuando coloco una etiqueta encima, la barra de progreso está oculta. Traté de crear una etiqueta transparente, pero tampoco funcionó, porque desapareció una vez que la barra de progreso comenzó a cambiar. – Svish

+0

Si crea un UserControl, intente colocar una ProgressBar primero (y tal vez 'SendItBack') luego coloque un control Label en ProgressBar. Deberia trabajar. El problema es cómo hacer que el fondo de Label sea transparente. Estoy trabajando en una solución para él en este momento ... – MaciekTalaska

+0

Hm, ahora que es interesante ... tendré que probarlo más adelante :) – Svish

4

Necesitaba hacer esto yo mismo y pensé que publicaría un ejemplo simplificado de mi solución ya que no pude encontrar ningún ejemplo. En realidad, es bastante simple si se utiliza la clase ProgressBarRenderer:

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

y didn ' ¿Mi solución funciona para ti? He probado en varias máquinas diferentes y parecía funcionar bien en todas ellas. – MaciekTalaska

+0

No lo intenté, acabo de publicar el código que había usado para dibujar una barra de progreso manualmente y luego agregué el bit de texto. –

+0

Esta es la mejor solución que he visto. –

11

Se podría anular WndProc y coger el mensaje WmPaint.

El siguiente ejemplo pinta la propiedad Texto de la barra de progreso en el centro.

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; 
     } 
    } 
} 
+0

Esta es la mejor solución para asegurarse – Kosmos

0

Aquí hay otra solución junto con las sugerencias de otras personas. Subclasé el control de la barra de progreso para que esto funcione. Mezclé y combiné códigos de varios lugares para esto. El evento de pintura podría ser más limpio, pero eso es para que lo haga;)

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