2009-10-04 132 views
5

認爲應該很容易創建一個ProgressBar,它自己繪製了一些文本。不過,我不太清楚這裏發生了什麼......C#:覆蓋ProgressBar上的OnPaint不工作?

我添加了以下兩個替代:

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,我得到它在new Rectangle(0, 0, Width, Height)發送,而不是畫在正確的地方文本的Bounds

我現在得到了文字,但ProgressBar已經不存在了......並且關鍵點是讓文字在ProgressBar之上。任何想法如何我可以解決這個問題?

回答

1

你的問題是你傳遞Bounds作爲你的Rectangle參數。邊界包含控件的高度和寬度,這是您想要的,但它也包含控件的頂部和左側屬性(相對於父窗體),因此您的「Hello」在控件上的偏移量無論多大控件在其父窗體上被抵消。

Bounds替換爲new Rectangle(0, 0, this.Width, this.Height),你應該看到你的「你好」。

+0

Oooh。接得好。 – Svish 2009-10-04 22:56:47

1

看來,如果您調用'SetStyle(ControlStyles.UserPaint,true)',則無法調用爲ProgressBar實現的標準OnPaint方法(使用base.OnPaint(e)根本不起作用)。最奇怪的是,即使你真的創建了一個UserControl,並試圖在進度條上繪製一些文本......它似乎也不工作......當然,你可以在其上放置一個標籤。 ..但我想這實際上並不是你想達到的。

好吧,似乎我設法解決了這個問題。它雖然有點複雜。首先你需要創建一個透明的Label控件。代碼如下:

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

第二件事是創建UserControl,將一個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控件的這種奇怪的行爲是我負責的,它不可能使用Graphics對象在從ProgressBar派生的控件上繪製任何東西。文本(或者你使用Graphics對象繪製的任何東西)實際上是繪製出來的,但是...在ProgressBar控件背後(如果仔細觀察,當ProgressBar的值發生變化時,您可能會看到此用戶繪製的東西閃爍,並且需要重新繪製自己)。

+0

嗯,它實際上是我想要實現的。問題是,當我在其上放置標籤時,進度條被隱藏。我試圖創建一個透明標籤,但這也不起作用,因爲一旦進度條開始改變,它就會消失。 – Svish 2009-10-05 13:30:39

+0

如果您創建一個UserControl,請嘗試先放置一個ProgressBar(也可能是'SendItBack'),然後將一個Label控件放到ProgressBar上。應該管用。問題是,如何使Label的背景變得透明 - 我正在爲此提供一個解決方案... – MaciekTalaska 2009-10-05 14:56:21

+0

嗯,現在很有意思...以後要試試這個:) – Svish 2009-10-05 18:54:33

4

我需要自己做這個,我想我會發布我的解決方案的簡化示例,因爲我找不到任何示例。這其實是很簡單,如果你使用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

並且didn'我的解決方案適合你嗎?我已經在幾臺不同的機器上進行了測試,並且它們在所有這些機器上都可以正常工作。 – MaciekTalaska 2010-04-13 14:56:20

+0

我沒有嘗試它,我只是發佈了我用來手動繪製進度條然後添加文本位的代碼。 – 2010-04-13 17:00:48

+0

這是我見過的最好的解決方案。 – 2012-08-20 05:32:26

11

你可以重寫的WndProc和趕上WmPaint消息。

下面的示例繪製了其中心的進度條的Text屬性。

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

這是最好的解決方案 – Kosmos 2013-08-24 11:57:31

0

這是另一個解決方案以及其他人的建議。我將進度條控件分類爲這個工作。我混合並匹配來自不同地方的代碼。油漆事件可能會更清潔,但這是你要做的;)

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