How to display a progress indicator in pure C/C++ (cout/printf)?

110,301

Solution 1

With a fixed width of your output, use something like the following:

float progress = 0.0;
while (progress < 1.0) {
    int barWidth = 70;

    std::cout << "[";
    int pos = barWidth * progress;
    for (int i = 0; i < barWidth; ++i) {
        if (i < pos) std::cout << "=";
        else if (i == pos) std::cout << ">";
        else std::cout << " ";
    }
    std::cout << "] " << int(progress * 100.0) << " %\r";
    std::cout.flush();

    progress += 0.16; // for demonstration only
}
std::cout << std::endl;

http://ideone.com/Yg8NKj

[>                                                                     ] 0 %
[===========>                                                          ] 15 %
[======================>                                               ] 31 %
[=================================>                                    ] 47 %
[============================================>                         ] 63 %
[========================================================>             ] 80 %
[===================================================================>  ] 96 %

Note that this output is shown one line below each other, but in a terminal emulator (I think also in Windows command line) it will be printed on the same line.

At the very end, don't forget to print a newline before printing more stuff.

If you want to remove the bar at the end, you have to overwrite it with spaces, to print something shorter like for example "Done.".

Also, the same can of course be done using printf in C; adapting the code above should be straight-forward.

Solution 2

You can use a "carriage return" (\r) without a line-feed (\n), and hope your console does the right thing.

Solution 3

For a C solution with an adjustable progress bar width, you can use the following:

#define PBSTR "||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||"
#define PBWIDTH 60

void printProgress(double percentage) {
    int val = (int) (percentage * 100);
    int lpad = (int) (percentage * PBWIDTH);
    int rpad = PBWIDTH - lpad;
    printf("\r%3d%% [%.*s%*s]", val, lpad, PBSTR, rpad, "");
    fflush(stdout);
}

It will output something like this:

 75% [||||||||||||||||||||||||||||||||||||||||||               ]

Solution 4

Take a look at boost progress_display

http://www.boost.org/doc/libs/1_52_0/libs/timer/doc/original_timer.html#Class%20progress_display

I think it may do what you need and I believe it is a header only library so nothing to link

Solution 5

You can print a carriage return character (\r) to move the output "cursor" back to the beginning of the current line.

For a more sophisticated approach, take a look at something like ncurses (an API for console text-based interfaces).

Share:
110,301
xmllmx
Author by

xmllmx

Updated on July 08, 2022

Comments

  • xmllmx
    xmllmx almost 2 years

    I'm writing a console program in C++ to download a large file. I know the file size, and I start a work thread to download it. I want to show a progress indicator to make it look cooler.

    How can I display different strings at different times, but at the same position, in cout or printf?

  • leemes
    leemes over 11 years
    + manual flush, otherwise it will not be shown immediately because the output is buffered.
  • leemes
    leemes over 11 years
    + manual flush, otherwise it will not be shown immediately because the output is buffered.
  • Alexey Frunze
    Alexey Frunze over 11 years
    + '\b' for moving the cursor one position left.
  • Ali
    Ali over 11 years
    And if the user accidentaly hits the enter it breaks down :( Apart from that, it is perhaps the most portable solution, +1.
  • leemes
    leemes over 11 years
    @Ali To avoid that, you would have to disable echoing (see man termios)
  • Ali
    Ali over 11 years
    @leemes #include <termios.h>, try that on M$ Windows :) Anyway, thanks for the tip, I will probably try that on Linux.
  • Leo
    Leo over 11 years
    +1 for ncurses. Definitely the way to go if you want to do anything a bit more complex.
  • leemes
    leemes over 11 years
    @Ali There might be an equivalent for W1ndOw$, but I don't know it. ;)
  • Robb1
    Robb1 almost 7 years
    Watch out, there should be no ';' at the end of the first #define!
  • horro
    horro over 6 years
    This is the simplest and best solution I have found so far
  • YuMS
    YuMS over 5 years
    Using "\r\e[0K" could also help clean the line. (tested under linux)
  • momo123
    momo123 about 4 years
    Is there a way to display an ascii character instead of | ? Thanks
  • Sylvain
    Sylvain about 3 years
    What is the meaning of the last part, why is there a "" for the last argument of the printf() ?
  • razz
    razz about 3 years
    @Sylvain The string in the square brackets has two parts; left and right. The left part consists of lpad characters of PBSTR printed using the %.*s specifier, while the right part consists of rpad length of a space left-padded string which we chose to be empty "" so that we only print rpad spaces using the %*s specifier.
  • Sylvain
    Sylvain almost 3 years
    Oh the right side is already "space left-padded". Thanks !! Great solution indeed.
  • Felierix
    Felierix about 2 years
    You don't use system() and especially the color command. Use SetConsoleTextAttribute(hConsole, color) instead and don't forget to reset (color 7).
  • XorOrNor
    XorOrNor about 2 years
    I think "percentage" parameter name is misleading as the function expects fraction of one ie. 0.1, 0.2, 0.5 and so on, not the percentage ie. 10.0, 20.0, 50.0.