2009-10-04 21 views
5

Myślałeś, że powinno być całkiem łatwe stworzenie ProgressBar, które narysowało trochę tekstu. Jednak nie jestem pewien, co się tu dzieje ...C#: Nadpisanie OnPaint na ProgressBar nie działa?

Dodałem dwa następujące przesłonięcia:

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

jednak uzyskać żadnego tekstu, jak i metody nawet nie wydają się być wywołana . Co tu się dzieje?


Aktualizacja: Dzięki dwie odpowiedzi tak daleko, mam zdobyć to rzeczywiście wywołać OnPaint za pomocą i mam zdobyć go wyciągnąć tekst w odpowiednim miejscu, wysyłając w new Rectangle(0, 0, Width, Height) zamiast z Bounds.

Dostaję teraz tekst, ale ProgressBar zniknął ... a punktem był rodzaj tekstu na górze ProgressBar. Każdy pomysł, jak mogę to rozwiązać?

Odpowiedz

1

Twój problem polega na tym, że podajesz Bounds jako parametr Rectangle. Ograniczenia zawierają wysokość i szerokość kontrolki, która jest tym, czego potrzebujesz, ale zawiera również właściwości Górna i Lewa kontrolki, w stosunku do formy nadrzędnej, więc Twoje "Cześć" jest odsuwane od kontroli przez kontrola jest przesunięta w stosunku do formy nadrzędnej.

Wymień Bounds na new Rectangle(0, 0, this.Width, this.Height) i powinieneś zobaczyć "Hello".

+0

Oooh. Dobry połów. – Svish

1

Wygląda na to, że jeśli wywołasz "SetStyle" (ControlStyles.UserPaint, true), nie można wywołać standardowej metody OnPaint dla ProgressBar (użycie base.OnPaint (e) w ogóle nie działa). Najdziwniejsze jest to, że nawet jeśli faktycznie tworzysz UserControl i próbujesz narysować jakiś tekst na pasku postępu ... to nie wydaje się działać zbyt ... Oczywiście możesz umieścić na nim etykietę. .. ale przypuszczam, że to nie jest to, co chcesz osiągnąć.

OK, wygląda na to, że udało mi się rozwiązać ten problem. Jest to trochę skomplikowane. Najpierw musisz utworzyć przejrzysty kontrolek Label. Kod poniżej:

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

Drugą sprawą jest utworzenie UserControl, umieszczenie na nim paska postępu (Dock = Fill) - będzie to kontrola, której użyjemy zamiast standardowego ProgressBar. Kod:

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

Dziwną rzeczą w ProgressBar jest to, że "przesuwa" kontrolki, które są na niej umieszczane, więc konieczne jest wysłanie paska postępu do tyłu i przeniesienie kontroli etykiety na wierzch. Nie znalazłem w tej chwili bardziej eleganckiego rozwiązania. To działa, etykieta jest wyświetlana na pasku postępu, tło kontrolki etykiety jest przezroczyste, więc myślę, że wygląda na to, że chcesz wyglądać :)

Mogę udostępnić mój przykładowy kod, jeśli chcesz ..

Och, przy okazji. to dziwne zachowanie kontrolki ProgressBar, o którym wspomniałem, jest odpowiedzialne za to, że nie można używać obiektu Graphics do rysowania czegokolwiek na formantu, który pochodzi z ProgressBar. Tekst (lub cokolwiek, co rysujesz za pomocą obiektu Graphics) jest aktualnie rysowany, ale ... za kontrolką ProgressBar (jeśli przyjrzysz się bliżej, możesz zobaczyć, jak te rysunki użytkownika migoczą, gdy wartość ProgressBar zmienia się i musi odświeża się).

+0

Tak naprawdę to właśnie chcę osiągnąć. Problem polega na tym, że kiedy umieszczam na nim etykietę, pasek postępu jest ukryty. Próbowałem utworzyć przezroczystą etykietę, ale to też nie działało, ponieważ zniknęło, gdy pasek postępu zaczął się zmieniać. – Svish

+0

Jeśli utworzysz UserControl, spróbuj najpierw umieścić ProgressBar (i może "SendItBack"), a następnie umieść kontrolkę Label na ProgressBar. Powinno działać. Problem w tym, jak sprawić, by tło Label było przezroczyste - Pracuję nad rozwiązaniem w tej chwili ... – MaciekTalaska

+0

Hm, teraz to jest interesujące ... będę musiał wypróbować ten jeden później :) – Svish

4

Potrzebowałem zrobić to sam i pomyślałem, że zamieściłbym uproszczony przykład mojego rozwiązania, ponieważ nie mogłem znaleźć żadnych przykładów. To rzeczywiście bardzo proste, jeśli użyć klasy 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

i didn ' t moje rozwiązanie działa dla ciebie? Przetestowałem na kilku różnych maszynach i wydawało się, że działają dobrze na nich wszystkich. – MaciekTalaska

+0

Nie próbowałem tego, właśnie opublikowałem kod, którego użyłem do ręcznego narysowania paska postępu, a następnie dodałem bit tekstowy. –

+0

To najlepsze rozwiązanie, jakie widziałem. –

11

mogłyby przesłonić WndProc i złapać wiadomość WmPaint.

Poniższy przykład rysuje właściwość Tekst paska postępu na środku.

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

To jest najlepsze rozwiązanie na pewno – Kosmos

0

Oto kolejne rozwiązanie wraz z sugestiami innych osób. Podklasowałem kontrolę paska postępu, aby to działało. Wymieszałem i dopasowałem kody z różnych miejsc. Zdarzenie z farbą może być czystsze, ale to do zrobienia;)

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