C++ Console Progress Indicator

后端 未结 4 660
一生所求
一生所求 2021-02-08 23:13

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 us

相关标签:
4条回答
  • 2021-02-08 23:45

    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.

    0 讨论(0)
  • 2021-02-08 23:46

    Wow, clipper, perhaps you are talking about the @row,col things built in to the language? (Rhetorical question only...)

    You can do simple progress bars with printf: you can leave out the trailing newline. You can obviously begin or end the string with \b in order to overprint characters. It's easy to do the traditional -\|/ kind that way.

    I recall that the Eclipse UI guidelines recommended progress indicators regardless of how much you were able to tell about the actual progress. I think theory was that anything is better than nothing and to just do the best you can.

    The only trick that you are likely to need is potentially to defeat line buffering. Be sure to fflush(stdout) after each output operation. (Or ostream::flush())

    0 讨论(0)
  • 2021-02-08 23:53

    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.

    0 讨论(0)
  • 2021-02-08 23:54

    Boost has a progress library which can help some of these things

    0 讨论(0)
提交回复
热议问题