如何在ProgressBar上放置文本?

我已经在我的c#桌面应用程序中使用ProgressBar控制。我已经在一个线程中使用它,而不是在其中声明控件的线程。它工作正常。 现在我想知道如何我可以显示一些文本里面的进度条控制像“启动注册”etc.Also我想用它作为选框进度条。请帮助我。

我将创build一个名为InfoProgresBar的控件,它提供了一个或两个标签(主作业,当前作业)和ProgressBar的function,并使用它来代替ProgressBar。

您将不得不重写OnPaint方法,调用基本实现并绘制自己的文本。

您将需要创build自己的CustomProgressBar ,然后重写OnPaint以绘制所需的任何文本。

自定义进度栏类

 namespace ProgressBarSample { public enum ProgressBarDisplayText { Percentage, CustomText } class CustomProgressBar: ProgressBar { //Property to set to decide whether to print a % or Text public ProgressBarDisplayText DisplayStyle { get; set; } //Property to hold the custom text public String CustomText { get; set; } public CustomProgressBar() { // Modify the ControlStyles flags //http://msdn.microsoft.com/en-us/library/system.windows.forms.controlstyles.aspx SetStyle(ControlStyles.UserPaint | ControlStyles.AllPaintingInWmPaint, true); } protected override void OnPaint(PaintEventArgs e) { Rectangle rect = ClientRectangle; Graphics g = e.Graphics; ProgressBarRenderer.DrawHorizontalBar(g, rect); rect.Inflate(-3, -3); if (Value > 0) { // As we doing this ourselves we need to draw the chunks on the progress bar Rectangle clip = new Rectangle(rect.X, rect.Y, (int)Math.Round(((float)Value / Maximum) * rect.Width), rect.Height); ProgressBarRenderer.DrawHorizontalChunks(g, clip); } // Set the Display text (Either a % amount or our custom text string text = DisplayStyle == ProgressBarDisplayText.Percentage ? Value.ToString() + '%' : CustomText; using (Font f = new Font(FontFamily.GenericSerif, 10)) { SizeF len = g.MeasureString(text, f); // Calculate the location of the text (the middle of progress bar) // Point location = new Point(Convert.ToInt32((rect.Width / 2) - (len.Width / 2)), Convert.ToInt32((rect.Height / 2) - (len.Height / 2))); Point location = new Point(Convert.ToInt32((Width / 2) - len.Width / 2), Convert.ToInt32((Height / 2) - len.Height / 2)); // The commented-out code will centre the text into the highlighted area only. This will centre the text regardless of the highlighted area. // Draw the custom text g.DrawString(text, f, Brushes.Red, location); } } } } 

示例WinForms应用程序

 using System; using System.Linq; using System.Windows.Forms; using System.Collections.Generic; namespace ProgressBarSample { public partial class Form1 : Form { public Form1() { InitializeComponent(); // Set our custom Style (% or text) customProgressBar1.DisplayStyle = ProgressBarDisplayText.CustomText; customProgressBar1.CustomText = "Initialising"; } private void btnReset_Click(object sender, EventArgs e) { customProgressBar1.Value = 0; btnStart.Enabled = true; } private void btnStart_Click(object sender, EventArgs e) { btnReset.Enabled = false; btnStart.Enabled = false; for (int i = 0; i < 101; i++) { customProgressBar1.Value = i; // Demo purposes only System.Threading.Thread.Sleep(100); // Set the custom text at different intervals for demo purposes if (i > 30 && i < 50) { customProgressBar1.CustomText = "Registering Account"; } if (i > 80) { customProgressBar1.CustomText = "Processing almost complete!"; } if (i >= 99) { customProgressBar1.CustomText = "Complete"; } } btnReset.Enabled = true; } } } 

避免闪烁文字

上面的Barry提供的解决scheme非常好,但是存在“闪烁问题”。

只要Value大于零,OnPaint就会被重复地调用,文本将闪烁。

这是一个解决scheme。 我们不需要VisualStyles的对象,因为我们将用我们自己的代码来绘制它。

将下面的代码添加到Barry写的自定义对象中,您将避免闪烁:

  [DllImportAttribute("uxtheme.dll")] private static extern int SetWindowTheme(IntPtr hWnd, string appname, string idlist); protected override void OnHandleCreated(EventArgs e) { SetWindowTheme(this.Handle, "", ""); base.OnHandleCreated(e); } 

我没有自己写这个。 它在这里find它: https : //stackoverflow.com/a/299983/1163954

我已经testing了它,它的工作原理。

我使用这个简单的代码,它的工作!

 for (int i = 0; i < N * N; i++) { Thread.Sleep(50); progressBar1.BeginInvoke(new Action(() => progressBar1.Value = i)); progressBar1.CreateGraphics().DrawString(i.ToString() + "%", new Font("Arial", (float)10.25, FontStyle.Bold), Brushes.Red, new PointF(progressBar1.Width / 2 - 10, progressBar1.Height / 2 - 7)); } 

只是有一个问题,当进度条开始上升时,有时会隐藏百分比,然后再出现。 我没有自己写。我在这里find它: c#中的进度条上的文字

我用了,工作。

我试着在进度条上放置一个带有透明背景的标签,但从来没有正确地工作。 所以我发现巴里的解决scheme非常有用,虽然我错过了美丽的Vista风格的进度条。 所以我将Barry的解决scheme与http://www.dreamincode.net/forums/topic/243621-percent-into-progress-bar/合并,并设法保留原生进度条,同时在其上显示文本百分比或自定义文本。; 我也没有看到这个解决scheme闪烁。 对不起,挖掘和旧线程,但我今天需要这个,所以其他人可能也需要它。

 public enum ProgressBarDisplayText { Percentage, CustomText } class ProgressBarWithCaption : ProgressBar { //Property to set to decide whether to print a % or Text private ProgressBarDisplayText m_DisplayStyle; public ProgressBarDisplayText DisplayStyle { get { return m_DisplayStyle; } set { m_DisplayStyle = value; } } //Property to hold the custom text private string m_CustomText; public string CustomText { get { return m_CustomText; } set { m_CustomText = value; this.Invalidate(); } } private const int WM_PAINT = 0x000F; protected override void WndProc(ref Message m) { base.WndProc(m); switch (m.Msg) { case WM_PAINT: int m_Percent = Convert.ToInt32((Convert.ToDouble(Value) / Convert.ToDouble(Maximum)) * 100); dynamic flags = TextFormatFlags.VerticalCenter | TextFormatFlags.HorizontalCenter | TextFormatFlags.SingleLine | TextFormatFlags.WordEllipsis; using (Graphics g = Graphics.FromHwnd(Handle)) { using (Brush textBrush = new SolidBrush(ForeColor)) { switch (DisplayStyle) { case ProgressBarDisplayText.CustomText: TextRenderer.DrawText(g, CustomText, new Font("Arial", Convert.ToSingle(8.25), FontStyle.Regular), new Rectangle(0, 0, this.Width, this.Height), Color.Black, flags); break; case ProgressBarDisplayText.Percentage: TextRenderer.DrawText(g, string.Format("{0}%", m_Percent), new Font("Arial", Convert.ToSingle(8.25), FontStyle.Regular), new Rectangle(0, 0, this.Width, this.Height), Color.Black, flags); break; } } } break; } } } 

我创build了一个使用TransparentLabel控件的InfoProgressBar控件。 如果使用定时器对表单进行testing,如果使用小于250毫秒的定时器间隔(可能是因为刷新屏幕所需的时间大于定时器间隔),则每30-40个值会发生一些小故障, 。

可以修改UpdateText方法将所有计算的值插入到CustomText中,但这不是我所需要的。 这将删除对DisplayType属性和枚举的需要。

TransparentLabel类是通过添加一个新的UserControl并将其更改为从Labelinheritance来创build的,具体实现如下:

 using System; using System.ComponentModel; using System.Drawing; using System.Windows.Forms; namespace Utils.GUI { public partial class TransparentLabel : Label { // hide the BackColor attribute as much as possible. // setting the base value has no effect as drawing the // background is disabled [Browsable(false)] [EditorBrowsable(EditorBrowsableState.Never)] public override Color BackColor { get { return Color.Transparent; } set { } } protected override CreateParams CreateParams { get { CreateParams cp = base.CreateParams; cp.ExStyle |= 0x20; // WS_EX_TRANSPARENT return cp; } } public override string Text { get { return base.Text; } set { base.Text = value; if(Parent != null) Parent.Invalidate(Bounds, false); } } public override ContentAlignment TextAlign { get { return base.TextAlign; } set { base.TextAlign = value; if(Parent != null) Parent.Invalidate(Bounds, false); } } public TransparentLabel() { InitializeComponent(); SetStyle(ControlStyles.Opaque, true); SetStyle(ControlStyles.OptimizedDoubleBuffer, false); base.BackColor = Color.Transparent; } protected override void OnMove(EventArgs e) { base.OnMove(e); RecreateHandle(); } protected override void OnPaintBackground(PaintEventArgs pevent) { // do nothing } } } 

我没有对相关的devise器代码做任何修改,但这里是为了完整。

 namespace Utils.GUI { partial class TransparentLabel { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if(disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { components = new System.ComponentModel.Container(); } #endregion } } 

然后,我创build了另一个新的UserControl,并将其更改为从ProgressBar派生,具有以下实现:

 using System.Collections; using System.ComponentModel; using System.ComponentModel.Design; using System.Drawing; using System.Windows.Forms; using System.Windows.Forms.Design; using System.Windows.Forms.Design.Behavior; namespace Utils.GUI { [Designer(typeof(InfoProgressBarDesigner))] public partial class InfoProgressBar : ProgressBar { // designer class to add font baseline snapline by copying it from the label private class InfoProgressBarDesigner : ControlDesigner { public override IList SnapLines { get { IList snapLines = base.SnapLines; InfoProgressBar control = Control as InfoProgressBar; if(control != null) { using(IDesigner designer = TypeDescriptor.CreateDesigner(control.lblText, typeof(IDesigner))) { if(designer != null) { designer.Initialize(control.lblText); ControlDesigner boxDesigner = designer as ControlDesigner; if(boxDesigner != null) { foreach(SnapLine line in boxDesigner.SnapLines) { if(line.SnapLineType == SnapLineType.Baseline) { snapLines.Add(new SnapLine(SnapLineType.Baseline, line.Offset, line.Filter, line.Priority)); break; } } } } } } return snapLines; } } } // enum to select the type of displayed value public enum ProgressBarDisplayType { Custom = 0, Percent = 1, Progress = 2, Remain = 3, Value = 4, } private string _customText; private ProgressBarDisplayType _displayType; private int _range; [Bindable(false)] [Browsable(true)] [DefaultValue("{0}")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] // {0} is replaced with the result of the selected calculation public string CustomText { get { return _customText; } set { _customText = value; UpdateText(); } } [Bindable(false)] [Browsable(true)] [DefaultValue(ProgressBarDisplayType.Percent)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public ProgressBarDisplayType DisplayType { get { return _displayType; } set { _displayType = value; UpdateText(); } } [Bindable(false)] [Browsable(true)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] // don't use the lblText font as if it is null, it checks the parent font (ie this property) and gives an infinite loop public override Font Font { get { return base.Font; } set { base.Font = value; } } [Bindable(false)] [Browsable(true)] [DefaultValue(100)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public new int Maximum { get { return base.Maximum; } set { base.Maximum = value; _range = base.Maximum - base.Minimum; UpdateText(); } } [Bindable(false)] [Browsable(true)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public new int Minimum { get { return base.Minimum; } set { base.Minimum = value; _range = base.Maximum - base.Minimum; UpdateText(); } } [Bindable(false)] [Browsable(true)] [DefaultValue(ContentAlignment.MiddleLeft)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public ContentAlignment TextAlign { get { return lblText.TextAlign; } set { lblText.TextAlign = value; } } [Bindable(false)] [Browsable(true)] [DefaultValue(typeof(Color), "0x000000")] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public Color TextColor { get { return lblText.ForeColor; } set { lblText.ForeColor = value; } } [Bindable(false)] [Browsable(true)] [DefaultValue(0)] [DesignerSerializationVisibility(DesignerSerializationVisibility.Visible)] [EditorBrowsable(EditorBrowsableState.Always)] public new int Value { get { return base.Value; } set { base.Value = value; UpdateText(); } } public InfoProgressBar() { InitializeComponent(); CustomText = "{0}"; DisplayType = ProgressBarDisplayType.Percent; Maximum = 100; Minimum = 0; TextAlign = ContentAlignment.MiddleLeft; TextColor = Color.Black; Value = 0; // means the label gets drawn in front of the progress bar lblText.Parent = this; _range = base.Maximum - base.Minimum; } protected void UpdateText() { switch(DisplayType) { case ProgressBarDisplayType.Custom: { lblText.Text = _customText; break; } case ProgressBarDisplayType.Percent: { if(_range > 0) { lblText.Text = string.Format(_customText, string.Format("{0}%", (int)((Value * 100) / _range))); } else { lblText.Text = "100%"; } break; } case ProgressBarDisplayType.Progress: { lblText.Text = string.Format(_customText, (Value - Minimum)); break; } case ProgressBarDisplayType.Remain: { lblText.Text = string.Format(_customText, (Maximum - Value)); break; } case ProgressBarDisplayType.Value: { lblText.Text = string.Format(_customText, Value); break; } } } public new void Increment(int value) { base.Increment(value); UpdateText(); } public new void PerformStep() { base.PerformStep(); UpdateText(); } } } 

而devise师的代码是:

 namespace Utils.GUI { partial class InfoProgressBar { /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.IContainer components = null; /// <summary> /// Clean up any resources being used. /// </summary> /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param> protected override void Dispose(bool disposing) { if(disposing && (components != null)) { components.Dispose(); } base.Dispose(disposing); } #region Component Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.lblText = new Utils.GUI.TransparentLabel(); this.SuspendLayout(); // // lblText // this.lblText.BackColor = System.Drawing.Color.Transparent; this.lblText.Dock = System.Windows.Forms.DockStyle.Fill; this.lblText.Location = new System.Drawing.Point(0, 0); this.lblText.Name = "lblText"; this.lblText.Padding = new System.Windows.Forms.Padding(3, 0, 3, 0); this.lblText.Size = new System.Drawing.Size(100, 23); this.lblText.TabIndex = 0; this.lblText.Text = "transparentLabel1"; this.ResumeLayout(false); } #endregion private TransparentLabel lblText; } } 

一般而言,您可以尝试放置一个Label控件,并将其放在进度条控件的顶部。 然后你可以设置你想要的标签文字。 我没有这样做我的自我。 如果它起作用,它应该是一个简单的解决scheme,而不是重写onpaint。