Making a console progress bar? (Windows)
Asked Answered
K

3

7

So I have a function (or rather, I'll turn it into a function later) to make a random % progress in a console window; like this:

#include <iostream>
#include <time.h>
#include <cmath>
#include <windows.h>

using namespace std;

int main()
{
    srand(time(0));
    int x = 0;

    for(int i = 0; i<100; i++){
        int r = rand() % 1000;
        x++;
        cout << "\r" << x << "% completed." << flush;
        if(i < 43){
           Sleep(r/6);
        }else if(i > 43 && i < 74){
           Sleep(r/8);
        }else if(i < 98){
           Sleep(r/5);
        }else if(i > 97 && i != 99){
           Sleep(2000);
        }
    }

    cout << endl << endl << "Operation completed successfully.\n" << flush;
    return 0;
}

The thing is, I want the output to be like this:

1% completed

|

(later...)

25% completed

|||||||||||||||||||||||||

How can I do that?

Thanks in advance!

Kocher answered 19/5, 2013 at 14:33 Comment(1)
Over two lines, you can't. How about on one line "X% completed |||||" ... "XX% completed |||||||||||" ... ?Hitandrun
T
15

Printing character '\r' is useful. It puts the cursor at the beginning of the line.

Since you can not access to previous line anymore, you can have something like this:

25% completed: ||||||||||||||||||

After each iteration:

int X;

...

std::cout << "\r" << percent << "% completed: ";

std::cout << std::string(X, '|');

std::cout.flush();

Also, you can use: Portable text based console manipulator

Turmeric answered 19/5, 2013 at 14:42 Comment(6)
Thank you, it works! But is there no way to do it over two lines?Kocher
Oh, but for some reason, it breaks the % counter.. After 66%, when it reaches the console edge, it keeps printing out the % completed on a new lineKocher
Try to avoid the number of | exceeds the line length.Turmeric
No user is ever going to count off a hundred | characters. Make it obvious and simple by displaying the full range, like |||*****.Hydrophilous
Try printing one | for every 20% completed. Change the ratio of | to percent complete to suit your needs.Opinionative
std::cout << std::string( X, '|' ); instead of for.Dorrie
T
0

I think this looks better:

#include <iostream>
#include <iomanip>
#include <time.h>
#include <cmath>
#include <windows.h>
#include <string>

using namespace std;
string printProg(int);

int main()
{
    srand(time(0));
    int x = 0;
    cout << "Working ..." << endl;
    for(int i = 0; i<100; i++){
        int r = rand() % 1000;
        x++;
        cout << "\r" << setw(-20) << printProg(x) << " " << x << "% completed." << flush;
        if(i < 43){
           Sleep(r/6);
        }else if(i > 43 && i < 74){
           Sleep(r/8);
        }else if(i < 98){
           Sleep(r/5);
        }else if(i > 97 && i != 99){
           Sleep(1000);
        }
    }

    cout << endl << endl << "Operation completed successfully.\n" << flush;
    return 0;
}

string printProg(int x){
    string s;
    s="[";
    for (int i=1;i<=(100/2);i++){
        if (i<=(x/2) || x==100)
            s+="=";
        else if (i==(x/2))
            s+=">";
        else
            s+=" ";
    }

    s+="]";
    return s;
}
Trepang answered 11/12, 2013 at 19:52 Comment(0)
H
-1

Use graphics.h or use more advanced WinBGI library. Download it and place the library files and the graphics.h file in appropriate locations in your project. Then just use the function named gotoxy(int x, int y) where x and y are in character places(not pixels) Consider your console window in the 4th quadrant of a Cartesian 2D axes system. But x and y starts typically from 1 upto n(depending on the size of the console window). You just have to clear the screen each time progress happens like this

    system("cls");   

as cls is the command for this in case of windows. Otherwise for linux/Mac use

    system("clear");

Now this function is in stdlib.h header. After that you can easily update the progress bar and write anywhere in it. But the progress bar you are using is discontinuous. There is more efficient way is to use

# Print iterations progress
def printProgressBar (iteration, total, prefix = '', suffix = '', decimals = 1, length = 100, fill = '█'):
    """
    Call in a loop to create terminal progress bar
    @params:
        iteration   - Required  : current iteration (Int)
        total       - Required  : total iterations (Int)
        prefix      - Optional  : prefix string (Str)
        suffix      - Optional  : suffix string (Str)
        decimals    - Optional  : positive number of decimals in percent complete (Int)
        length      - Optional  : character length of bar (Int)
        fill        - Optional  : bar fill character (Str)
    """
    percent = ("{0:." + str(decimals) + "f}").format(100 * (iteration / float(total)))
    filledLength = int(length * iteration // total)
    bar = fill * filledLength + '-' * (length - filledLength)
    print('\r%s |%s| %s%% %s' % (prefix, bar, percent, suffix), end = '\r')
    # Print New Line on Complete
    if iteration == total: 
        print()

# 
# Sample Usage
# 

from time import sleep

# A List of Items
items = list(range(0, 57))
l = len(items)

# Initial call to print 0% progress
printProgressBar(0, l, prefix = 'Progress:', suffix = 'Complete', length = 50)
for i, item in enumerate(items):
    # Do stuff...
    sleep(0.1)
    # Update Progress Bar
    printProgressBar(i + 1, l, prefix = 'Progress:', suffix = 'Complete', length = 50)

# Sample Output
Progress: |█████████████████████████████████████████████-----| 90.0% Complete
Haemic answered 13/1, 2019 at 15:0 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.