Home > Software engineering >  What's an efficient way to display text of a progress bar?
What's an efficient way to display text of a progress bar?

Time:03-23

I'm working on a GUI for a CNC machine. We have load cells that output a voltage depending on how much force is applied to the cell, which the machine can read and then display to the operator so they know how much force they are clamping a part with.

Microsoft's website says .NET Framework 4.6.1 (which I'm building with) progress bars have a text property, but setting the text itself doesn't display it. I found a different way of doing it like this:

int loadVal = 0;
string progBarText = "";
SizeF textSize;
Graphics graphics = CreateGraphics();
Font font = new Font("Lucida Console", FontHeight = 11, FontStyle.Regular);

leftClampProgBar.SuspendLayout();
rightClampProgBar.SuspendLayout();


            

//~~~~Left Clamp~~~~~~
loadVal = (PLC_ushLeftClampLoad * 500) / 65535;
leftClampProgBar.Value = (loadVal * 100) / 500;

//setting the text for the progress bar
progBarText = loadVal.ToString()   " Lb(s)";

//have to figure out how big the text is
textSize = graphics.MeasureString(progBarText, font);

//drawing the text to the progress bar
leftClampProgBar.CreateGraphics().DrawString(
    progBarText,
    font,
    Brushes.Black,
    new PointF((leftClampProgBar.Width - textSize.Width) / 2,
    (leftClampProgBar.Height - textSize.Height) / 2));;


//~~~~~Right Clamp~~~~~~
loadVal = (PLC_ushRightClampLoad * 500) / 65535;
rightClampProgBar.Value = (loadVal * 100) / 500;

//setting the text for the progress bar
progBarText = loadVal.ToString()   " Lb(s)";

//have to figure out how big the text is
textSize = graphics.MeasureString(progBarText, font);

//drawing the text to the progress bar
rightClampProgBar.CreateGraphics().DrawString(
    progBarText,
    font,
    Brushes.Black,
    new PointF((rightClampProgBar.Width - textSize.Width) / 2, 
    (rightClampProgBar.Height - textSize.Height) / 2));

//AddNotification("Right Clamp: "   loadVal, Color.Purple);
leftClampProgBar.ResumeLayout();
rightClampProgBar.ResumeLayout();

However, this leads to the the text sometimes being printed wrong, or it is not refreshing correctly. The method the code above is in gets called by a timer every 500ms and causes the GUI to act a little slower than before. I could make a different timer for this specifically that has a larger interval, but I wanted to know if there was a more efficient way to display the text at all, not worrying about how often the timer repaints it. progress bar text

CodePudding user response:

I would recommend just having a separate label above the progress-bar that you update. This should be far simpler, and probably also being easier to read.

If you insist on printing the text on top of the progress-bar you should consider creating your own class that derives from progress-bar and override the onPaint method. But if you use this approach you need to consider contrast and legibility as the text and progress overlaps.

CodePudding user response:

You could create custom progress bar to do this. The following class assumes ProgressBarRenderer.IsSupported results in true and does not animate progress bar.

public class TextProgressBar : ProgressBar
{
    public TextProgressBar() : base()
    {
        SetStyle(ControlStyles.UserPaint, true);
        DoubleBuffered = true; // remove flicker
    }

    // unhide Text/Font Properties and force changes to re-render control

    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public override string Text
    {
        get => base.Text;
        set
        {
            base.Text = value;
            Refresh();
        }
    }

    [Browsable(true)]
    [EditorBrowsable(EditorBrowsableState.Always)]
    public override Font Font
    {
        get => base.Font;
        set
        {
            base.Font = value;
            if (!string.IsNullOrWhiteSpace(Text)) Refresh();
        }
    }

    protected override void OnPaintBackground(PaintEventArgs pevent)
    {
        base.OnPaintBackground(pevent);

        // draw progress bar background
        ProgressBarRenderer.DrawHorizontalBar(pevent.Graphics, new Rectangle(0, 0, Width, Height));
    }

    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);

        // draw progress on progress bar
        double percentage = ((double)(Value - Minimum)) / ((double)(Maximum - Minimum));
        ProgressBarRenderer.DrawHorizontalChunks(e.Graphics, new Rectangle(0, 0, (int)(Width * percentage), Height));

        // draw text on progress bar
        using (Brush brush = new SolidBrush(ForeColor))
        {
            // get rendered size of text
            var size = e.Graphics.MeasureString(Text, Font, new SizeF(Width, Height));

            // calculate location to center text on progress bar
            var location = new PointF((Width - size.Width) * 0.5f, (Height - size.Height) * 0.5f);

            // draw text
            e.Graphics.DrawString(Text, Font, brush, new RectangleF(location, size));
        }
    }
}
  • Related