8

I was downloading a compiler (I think it was MinGW but I'm not sure) on windows 2000 the other day (I'm generally a Mac user, but it wasn't my machine), and the downloader was a MS-DOS command line app that would display a progress bar for the download. Something like this...

|---                 | 15%
...
|------              | 30%
...
...
|--------------      | 70%

except that it would continuously update on the same line. I assume the program accomplished this by deleting previously printed characters and reprinting different ones, but I can't seem to figure out how to do this.

I've tried to print a 'delete' character several different ways, like (char)8 and \b (even \r, which I heard backtracks to the beginning of the line in some languages), but none of those things worked.

Does anyone know how to do this sort of stuff?

Edit: This question has become platform-specific. I want to know specifically how to accomplish this on a Mac.

Michael Dorst
  • 8,210
  • 11
  • 44
  • 71
  • 1
    Related: http://stackoverflow.com/questions/60221/how-to-animate-the-command-line?rq=1 – Pubby Jun 30 '12 at 04:24
  • clrscr would clear the whole screen, and on the mac all it does is print enough newlines to move everything off the screen (meaning you can still scroll back to it, which is useful, but also annoying). – Michael Dorst Jun 30 '12 at 04:26
  • http://en.wikipedia.org/wiki/Ncurses – Mooing Duck Jun 30 '12 at 05:30
  • @MooingDuck: That's overkill and less portable than you'd like. There is `boost::progress_display`. – Benjamin Bannier Jun 30 '12 at 06:55
  • @honk: overkill? Probably. But I've been led to believe it works on windows/linux/mac, and I knew of no other library. Good to know aboout progress_display now, that's neat! – Mooing Duck Jun 30 '12 at 16:28

2 Answers2

6

I'm not sure why you ran into problems, but either \b or \r can be used to do this, I have used \b.

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

// This is the only non-portable part of this code.
// Simply pause for a specified number of milliseconds
// For Windows, we just call Sleep. For Linux, you'd
// probably call nanosleep instead (with a suitable
// multiplier, of course). Most other systems (presumably)
// have (at least vaguely) similar capabilities.
void pause(int ms) { 
    Sleep(ms);
}

static const int width = 40;    

void show_percent(int i) {
     int dashes = (width * i)/100;

     std::cout << '|' << std::left << std::setw(width) << std::string(dashes, '-') << '|' << std::setw(3) << i << "%";
}

int main() {

    for (int i=0; i<101; i++) {
        show_percent(i);
        std::cout << std::string(width+6, '\b');
        pause(100);
    }
}
Jerry Coffin
  • 476,176
  • 80
  • 629
  • 1,111
  • I believe the portable way to do that in C++11 would be `std::this_thread::sleep_for(std::chrono::milliseconds(ms));` – Michael Dorst Jun 30 '12 at 04:38
  • My bad, I spaced out. I was so impressed with your show_percent code that I forgot to mention that the '\r' thing didn't work at all. I think it may have to do with the difference in the way Windows, Mac OS X and Linux represent newlines. – Michael Dorst Jun 30 '12 at 04:50
  • @MichaelDorst: Yeah, I hadn't thought of it until you mentioned it, but on the Mac, for years they've used `\r` as the 'new-line` character, so it's probably no surprise that it doesn't just go back to the beginning of the current line like it would on a sane system. I don't have a Mac to test with, but see if the modified code above works better. – Jerry Coffin Jun 30 '12 at 06:44
  • Nice! A variety of cross-platform ways of doing the sleep [here](http://stackoverflow.com/questions/10918206/cross-platform-sleep-function-for-c) – acraig5075 Jun 30 '12 at 07:27
  • Note: Carriage return ('\r') does work on Mac - it just doesn't work in the XCode console window. – 3Dave Sep 26 '19 at 21:29
4

According to Wikipedia:

The Win32 console does not support ANSI escape sequences at all. Software can manipulate the console with the ioctl-like Console API interlaced with the text output. Some software internally interprets ANSI escape sequences in text being printing and translates them to these calls [citation needed].

Check out this: http://msdn.microsoft.com/en-us/library/ms682073.aspx

I believe SetConsoleCursorPosition is what allows you to replace text.

Morwenn
  • 21,684
  • 12
  • 93
  • 152
Pubby
  • 51,882
  • 13
  • 139
  • 180