Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

C++ Console Progress Indicator

Tags:

c++

linux

console

What would be an easy way of implementing a console-based progress indicator for a task that's being executed, but I can't anticipate how much time it would take?

I used to do this back when I coded in Clipper, and it was only a matter of iterating through the chars '/', '-', '\', '|' and positioning them in the same place.

Any way / links / libs for doing that (or something similar) in C++?

The target for this is *nix environments.

Edits:

  • changed the title to be more coherent and generic;
  • added target environment.
like image 733
kolrie Avatar asked Sep 15 '09 03:09

kolrie


2 Answers

A very simple way to do it is to print out a string followed by a '\r' character. That is carriage return by itself and on most consoles, it returns the cursor to the beginning of the line without moving down. That allows you to overwrite the current line.

If you are writing to stdout or cout or clog remember to fflush or std::flush the stream to make it output the line immediately. If you are writing to stderr or cerr then the stream is unbuffered and all output is immediate (and inefficient).

A more complicated way to do it is to get into using a screen drawing library like curses. The Windows consoles have some other ways of setting them for direct screen writing but I don't know what they are.

like image 51
Zan Lynx Avatar answered Sep 23 '22 10:09

Zan Lynx


You could try something like:

void
spinner(int spin_seconds) {
    static char const spin_chars[] = "/-\\|";
    unsigned long i, num_iterations = (spin_seconds * 10);
    for (i=0; i<num_iterations; ++i) {
        putchar(spin_chars[i % sizeof(spin_chars)]);
        fflush(stdout);
        usleep(100000);
        putchar('\b');
    }
}

Of course, this is non-standard because of the sub-second usleep() and I'm not sure if there is any guarantee that \b erases a character or not, but it works on most platforms. You can also try \r instead if \b doesn't do the trick. Otherwise, try to find a version of curses.

Edit (curses sample)

This should get you started:

#include <curses.h>
#include <unistd.h>

void spinner(int spin_seconds) {
    static char const spin_chars[] = "/-\\|";
    unsigned long i, num_iterations = (spin_seconds * 10);
    for (i=0; i<num_iterations; ++i) {
        mvaddch(0, 0, spin_chars[i & 3]);
        refresh();
        usleep(100000);
    }
}

int main() {
    initscr();    /* initializes curses */
    spinner(10);  /* spin for 10 seconds */
    endwin();     /* cleanup curses */
    return 0;
}

Make sure to link with either -lcurses or -lncurses. That should work on any UNIX alike out there.

like image 32
D.Shawley Avatar answered Sep 22 '22 10:09

D.Shawley