Я использовал ProgressBar Control в моем рабочем приложении С#. Я использовал его в потоке, отличном от потока, в котором был объявлен элемент управления. Он работает Fine. Теперь мне интересно, как я могу показать какой-то текст внутри контрольного бара, например "Инициирование регистрации" и т.д. Также я хочу использовать его в качестве шага выполнения Marquee. Пожалуйста, помогите мне.
Как разместить текст на ProgressBar?
Ответ 1
Я создаю элемент управления, например, InfoProgresBar, которые предоставляют эту функциональность ярлыком или двумя (основное задание, текущее задание) и ProgressBar и используют его вместо этого ProgressBar.
Ответ 2
Вам придется переопределить метод OnPaint, вызвать базовую реализацию и нарисовать свой собственный текст.
Вам нужно будет создать свой собственный 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;
}
}
}
Ответ 3
ИЗБЕГАЙТЕ ТЕКСТ FLICKERING
решение, предоставленное Barry выше, отлично, но есть "проблема мерцания".
Как только значение будет выше нуля, OnPaint будет повторно отображаться и текст будет мерцать.
Это решение. Нам не нужны VisualStyles для объекта, так как мы будем рисовать его с помощью нашего собственного кода.
Добавьте следующий код к настраиваемому объекту, который написал Барри, и вы избегаете мерцания:
[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);
}
Я сам этого не писал. Он нашел это здесь: fooobar.com/questions/75877/...
Я тестировал его, и он работает.
Ответ 4
Я использовал этот простой код, и он работает!
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));
}
У него просто одна простая проблема, и вот она: когда индикатор выполнения начинает расти, процент несколько раз скрывается, а затем появляется снова. Я не написал это сам. Я нашел это здесь: текст на прогрессбар в С#
Я использовал этот код, и он работает.
Ответ 5
Я попробовал поместить ярлык с прозрачным фоном на индикатор выполнения, но так и не смог его правильно работать. Поэтому я нашел Barry решение здесь очень полезным, хотя я пропустил красивый индикатор прогресса Vista. Таким образом, я объединил решение Barry с http://www.dreamincode.net/forums/topic/243621-percent-into-progress-bar/ и сумел сохранить собственный индикатор выполнения, отображая над ним процент текста или пользовательский текст. Я тоже не вижу мерцания в этом решении. Извините, что выкопал и старый поток, но мне это было нужно сегодня, и другие могут нуждаться в нем.
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;
}
}
}
Ответ 6
Не писал не мигает/мерцание TextProgressBar
Не забудьте проголосовать за ответ, если этот кодекс поможет вам.
Вы можете найти исходный код здесь: https://github.com/ukushu/TextProgressBar
Образцы:
Ответ 7
Я создал элемент управления InfoProgressBar, который использует элемент управления TransparentLabel. Тестирование по форме с помощью таймера, я получаю некоторые небольшие сбои, отображающие текст каждые 30-40 значений, если используется интервал таймера менее 250 миллисекунд (вероятно, из-за времени, необходимого для обновления экрана, больше, чем интервал таймера).
Можно было бы изменить метод UpdateText, чтобы вставить все вычисленные значения в CustomText, но это еще не все, что мне нужно. Это устранит необходимость в свойстве DisplayType и перечислит.
Класс TransparentLabel был создан путем добавления нового UserControl и изменения его наследования на основе Label со следующей реализацией:
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
}
}
}
Я не внес никаких изменений в соответствующий конструкторский код, но здесь он для полноты.
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
}
}
Затем я создал еще один новый 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 (i.e. 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();
}
}
}
И код дизайнера:
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;
}
}
Ответ 8
В любом случае вы можете попытаться установить элемент управления Label и поместить его поверх контрольного индикатора выполнения. Затем вы можете установить текст, который хотите пометить. Я не сделал этого сам. Если он работает, это должно быть более простым решением, чем переопределять onpaint.