tags:

views:

728

answers:

5

My apologies for an inaccurate title, but I'm not sure what this is called exactly.

How would one print to the console a single, updating line?

For example, if I wanted to print a percent completion status every cycle but not flood the console with steams of text, how would I accomplish this? (What is this called? -- for future Googling)

Thank you!

+8  A: 

There is no portable way to clean the screen though there is a simple way to return to the beginning of the line using \r then overwriting what we wrote before. I am using Sleep from Windows API:

#include <iostream>
#include <windows.h>
using namespace std;

int main()
{
 for(int i = 1; i <= 10; i++)
 {
  std::cout << i*10 << '%';
  std::cout.flush(); // see wintermute's comment
  Sleep(1000);
  std::cout << '\r';
 }
}
AraK
For further illumination, '\r' outputs a carriage return.
Dan Moulding
You might want to call `std::cout.flush()` before `Sleep()` since `std::cout` is a buffered stream and hence it's contents may not be displayed when you expect.
Whisty
As Dan says, `\r` is a carriage return, which does not *clear* the line, it just moves the cursor back to the beginning of the line.
Graeme Perrow
@Dan Thanks. Edited :)
AraK
@wintermute Thanks for the suggestion. Can you provide a reference that says cout is buffered? I think I read long ago it isn't!
AraK
Weather this works will depend greatly on the console you are using. A lot of consoles ignore '\r'.
Martin York
@AraK - cerr (and C's stderr) are unbuffered, but cin and cout (and C's stdin and stdout) are almost always buffered.
Chris Lutz
@AraK: 27.3.1 Narrow stream objects: Point 2: 'The object cout controls output to a stream buffer associated with the object stdout'
Martin York
@Martin Thanks man. I've no idea why www.aristeia.com/Papers/C++ReportColumns/novdec95.pdf got stuck in my mind :)
AraK
+2  A: 

The basic solution is to:

loop:
    backspace (over written text)
    write (without newline)
    flush
    wait and get updates

Alternatively, you could try a solution using the curses library - though I'm not sure whether this is quite what you're after. Curses provides your basic ascii graphics for text based GUIs (sometimes called a TUI).

PinkTriangles
Curses is the only way to do this port ably. Note it assumes your console is part of the curses DB.
Martin York
+2  A: 

Curses is only way to do this portably.

A quick google led me too:

http://code.google.com/p/tinycurses/wiki/basic1

Martin York
I wouldn't say the "only" way. If the terminal is ANSI-compatible, you can output "\r" or '\015'. If it's VT-100-compatible, you can also output '\033[5n' to the TTY and the response will be along the lines of '\033[5;5R' and then you can send '\033[5;0H' to go to the beginning of line 5. That's all ncurses does anyway.
greyfade
A: 

How fast are your cycles? Are they in the millisecond, or seconds. If your cycles are short, you may only want to update the screen after a second as elpased.

For example

   include <time.h>  /* if memory serves me correctly */
   int currentTime = time(0);
   for ( int i = 0; i < 100; i++)
   {
     /* do work here  and save the percentage completed */
     lastTime = time(0);
     if ((lastTime-currentTime) >= 1 ) 
     {
       /* output percentage completed (using AraK information) */
       currentTime = lastTime;
     }
   }

This will only update the screen every second and save the time writing to the screen as it consumes time to redraw the screen (which you can use for processing). In addition, if your updates go so fast, this lets the user see the percentage if your cycles are quite short, as you could be redrawing the screen all of the time.

Note: Updated based on comments.

Glenn
Needs to be time(0). time() takes the address of a time_t, updating the referenced time_t if given.
Warren Young
Or you could just update it when the percentage actually increments, there's no point updating it if the same thing is going to be displayed, and with the number of draw calls not going past 101 (assuming a 0%->100% display), the drawing isn't going to have much impact on performance
Grant Peters
Thanks for the input. It's been a while since I have used the time function.
Glenn
A: 

This depends on the platform you are using. I'm not sure how you do this on Linux, but on Windows you can either use WriteConsole or SetConsoleCursorPosition to do this.

I don't believe a completely portable way to do this exists other than outputting a ton of backspaces as already mentioned. The backspace method can cause a lot of flicker which may be unacceptable in your application ... the Win32 functions do not cause flicker. Not sure about the curses library.

Billy ONeal