Search code examples
c#graphics.net-3.5pictureboxvisual-studio-2015

C# - ".FillRectangle" Not Completely Filling Rectangle


I'm using the following code as just a test for how I might use a custom progress bar in the future - it actually isn't a progress bar at all, but rather a picturebox that the code draws a rectangle on, and then fills up based on a timer.

The problem is, I'm reaching 100% before the box is filled. I've tinkered around, but not been able to locate the issue. What am I doing wrong? See code below, and imgur screenshot of the behavior on my system.

Thanks.

    public partial class frmLoading : Form
{
    System.Windows.Forms.Timer tLoading = new System.Windows.Forms.Timer();
    Double pbLoadingUnit;
    int pbLoadingWIDTH, pbLoadingHEIGHT, pbLoadingComplete;

    Bitmap bmpLoading;
    Graphics gLoading;

    private void frmLoading_Load(object sender, EventArgs e)
    {
        pbLoadingWIDTH = pictureLoading.Width;
        pbLoadingHEIGHT = pictureLoading.Height;
        pbLoadingUnit = pbLoadingWIDTH / 100;
        pbLoadingComplete = 0;
        bmpLoading = new Bitmap(pbLoadingWIDTH, pbLoadingHEIGHT);
        tLoading.Interval = 32;
        tLoading.Tick += new EventHandler(this.tLoading_Tick);
        tLoading.Start();
    }
    private void tLoading_Tick(object sender, EventArgs e)
    {
        gLoading = Graphics.FromImage(bmpLoading);
        gLoading.Clear(Color.DarkSlateGray);
        gLoading.FillRectangle(Brushes.DodgerBlue, new Rectangle(0, 0, (int)(pbLoadingComplete * pbLoadingUnit), pbLoadingHEIGHT));
        gLoading.DrawString(pbLoadingComplete + "%", new Font("Segoe UI Semibold", pbLoadingHEIGHT / 2), Brushes.White, new PointF(pbLoadingWIDTH / 2 - pbLoadingHEIGHT, pbLoadingHEIGHT / 10));
        pictureLoading.Image = bmpLoading;

        pbLoadingComplete++;
        if (pbLoadingComplete > 100)
        {
            gLoading.Dispose();
            tLoading.Stop();
        }
    }

Solution

  • You should change this

    pbLoadingUnit = pbLoadingWIDTH / 100;
    

    to this

    pbLoadingUnit = Convert.ToDouble(pbLoadingWIDTH) / 100;
    

    I assume your picture width is not a multiple of a hundred. With your old code, your pbLoadingUnit will be generate as integer since you divide integer to integer.

    You may use this too :

    double div = 100;
    pbLoadingUnit = pbLoadingWIDTH / div;
    

    OR

    pbLoadingUnit = pbLoadingWIDTH / Convert.ToDouble(100);
    

    The point is, you should get the double value of pbLoadingUnit.

    For more information about numeric casting, you may see this link dotnetperls.com/numeric-casts