2009-10-04 7 views
5

Đã nghĩ rằng việc tạo một số ProgressBar sẽ tự tạo ra một số văn bản. Tuy nhiên, tôi không hoàn toàn chắc chắn những gì đang xảy ra ở đây ...C#: Ghi đè OnPaint trên ProgressBar không hoạt động?

tôi thêm hai ghi đè sau:

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

Tuy nhiên, tôi không nhận được văn bản, và các phương pháp thậm chí không dường như được gọi là . Chuyện gì đang xảy ra ở đây?


Cập nhật: Nhờ có hai câu trả lời cho đến nay, tôi đã nhận được nó để thực sự gọi OnPaint bằng cách sử dụng , và tôi đã nhận nó để vẽ văn bản ở đúng nơi bằng cách gửi trong new Rectangle(0, 0, Width, Height) thay của Bounds.

Tôi nhận được văn bản ngay bây giờ, nhưng ProgressBar đã biến mất ... và điểm là loại có văn bản ở trên cùng của ProgressBar. Bất kỳ ý tưởng làm thế nào tôi có thể giải quyết điều này?

Trả lời

1

Vấn đề của bạn là bạn đang chuyển sang số Bounds làm thông số Hình chữ nhật. Các giới hạn chứa chiều cao và chiều rộng của điều khiển, đó là những gì bạn muốn, nhưng nó cũng chứa các thuộc tính trên cùng và bên trái của điều khiển của bạn, liên quan đến biểu mẫu gốc, vì vậy "Hello" của bạn đang được bù đắp trên bộ điều khiển. kiểm soát được bù đắp trên hình thức cha mẹ của nó.

Thay thế Bounds bằng new Rectangle(0, 0, this.Width, this.Height) và bạn sẽ thấy "Xin chào" của mình.

+0

Oooh. Nắm bắt tốt. – Svish

1

Có vẻ như nếu bạn gọi 'SetStyle (ControlStyles.UserPaint, true)' phương thức OnPaint chuẩn được triển khai cho ProgressBar không thể được gọi (sử dụng base.OnPaint (e) không hoạt động). Điều kỳ lạ nhất là ngay cả khi bạn thực sự tạo ra một UserControl, và cố gắng vẽ một số văn bản trên thanh tiến trình ... nó dường như không hoạt động ... Tất nhiên bạn có thể đặt một Nhãn lên trên nó. .. nhưng tôi cho rằng đó không phải là những gì bạn muốn đạt được.

Ok, có vẻ như tôi đã cố gắng giải quyết vấn đề này. Đó là mặc dù một chút phức tạp. Trước tiên, bạn cần tạo điều khiển Nhãn trong suốt. Mã bên dưới:

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

Điều thứ hai là tạo UserControl, đặt ProgressBar lên đó (Dock = Fill) - đây sẽ là điều khiển mà chúng tôi sẽ sử dụng thay vì ProgressBar chuẩn. Mã số:

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

Điều kỳ lạ với ProgressBar là nó 'rút' các điều khiển được đặt trên đó, vì vậy cần phải đẩy thanh tiến trình trở lại và mang nhãn kiểm soát về phía trước. Tôi đã không tìm thấy giải pháp thanh lịch hơn vào lúc này. Tác phẩm này, nhãn đang được hiển thị trên thanh tiến trình, nền của điều khiển nhãn là trong suốt, vì vậy tôi nghĩ có vẻ như bạn muốn nó trông :)

Tôi có thể chia sẻ mã mẫu nếu bạn muốn .. .

Ồ, btw. hành vi kỳ lạ này của điều khiển ProgressBar mà tôi đã đề cập, chịu trách nhiệm cho rằng không thể sử dụng đối tượng Đồ họa để vẽ bất kỳ thứ gì trên một điều khiển có nguồn gốc từ ProgressBar. Các văn bản (hoặc bất cứ điều gì bạn vẽ bằng cách sử dụng đối tượng đồ họa) thực sự được rút ra nhưng ... đằng sau điều khiển ProgressBar (nếu bạn nhìn kỹ hơn, bạn có thể thấy người dùng này vẽ mọi thứ nhấp nháy khi giá trị của ProgressBar thay đổi và nó cần phải tự sơn lại).

+0

Vâng, nó thực sự là những gì tôi muốn đạt được. Vấn đề là khi tôi đặt một nhãn lên trên nó, thanh tiến trình bị ẩn. Tôi đã cố tạo một nhãn trong suốt, nhưng điều đó không có tác dụng, vì nó biến mất khi thanh tiến trình bắt đầu thay đổi. – Svish

+0

Nếu bạn tạo UserControl, hãy thử đặt ProgressBar trước (và có thể là 'SendItBack') rồi đặt điều khiển Label lên ProgressBar. Nên làm việc. Vấn đề là, làm thế nào để làm cho nền của Label trong suốt - Tôi đang làm việc trên một giải pháp cho nó tại thời điểm này ... – MaciekTalaska

+0

Hm, bây giờ là thú vị ... sẽ phải thử này ra sau :) – Svish

4

Tôi cần tự làm điều này và tôi nghĩ rằng tôi sẽ đăng một ví dụ đơn giản về giải pháp của mình vì tôi không thể tìm thấy bất kỳ ví dụ nào. Nó thực sự khá đơn giản nếu bạn sử dụng lớp 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

và didn ' t giải pháp của tôi làm việc cho bạn? Tôi đã thử nghiệm trên vài máy khác nhau và nó có vẻ hoạt động tốt trên tất cả chúng. – MaciekTalaska

+0

Tôi đã không thử nó, tôi chỉ đăng các mã tôi đã sử dụng để vẽ một thanh tiến trình bằng tay và sau đó thêm bit văn bản. –

+0

Đây là giải pháp tốt nhất mà tôi đã thấy. –

11

Bạn có thể ghi đè WndProc và nhận thông báo WmPaint.

Ví dụ bên dưới vẽ thuộc tính Văn bản của thanh tiến trình ở chính giữa.

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

Đây là giải pháp tốt nhất cho chắc chắn – Kosmos

0

Đây là giải pháp khác cùng với đề xuất của người khác. Tôi đã phân lớp điều khiển thanh tiến trình để thực hiện công việc này. Tôi trộn lẫn và mã số phù hợp từ những nơi khác nhau cho việc này. Sự kiện sơn có thể sạch hơn, nhưng đó là để bạn làm;)

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