I'm coding a task monitoring, which updates tasks' progress using cout. I'd like to display one task progress per line, therefore I have to rollback several lines of the console.
I insist on "several" because \b
does the job for one line, but does not erase \n
between lines.
I tried std::cout.seekp(std::cout.tellp() - str.length());
but tellp()
returns -1 (failure).
You can do cout << '\r';
to jump to the beginning of the current line, but moving upwards is system-specific. For Unix, see man termcap
and man terminfo
(and search for cursor_up
). On ANSI-compatible terminals (such as most modern terminals available on Unix), this works to move up: cout << "\e[A";
.
Don't try seeking in cout
, it's unseekable most of the time (except when redirected to a file).
As mentioned in other answers, using the ncurses (or slang) library provides a good abstraction for terminal I/O on Unix.
Instead of filling with spaces (which is error-prone, because not every terminal is 80 characters wide), you can do \r
+ clr_eol
: std::cout << "\r\e[K" << std::flush
.
Use an output formatting library such as ncurses if you can; this simplifies terminal manipulation significantly.
Neither C nor C++ define anything like that. You need explicit terminal manipulation. On Unix you can use curses. Have no idea what's there for Windows.
I know this is an old post, but the accepted doesn't cover cases where cout is piped to a program or file and this is the top of my google searches. The following will handle both piped and non-piped stdout with slightly different behavior.
#include <iostream>
#include <functional>
#include <stdio.h>
#ifdef _WIN32
#include <io.h>
#else
#include <unistd.h>
#define _isatty isatty
#define _fileno fileno
#endif
const std::function<void(const size_t&)> progress_printer(_isatty(_fileno(stdout)) == 1 ?
[](const size_t& i) {
std::cout << "\rNumber " << i << std::flush;
} :
[](const size_t& i) {
static std::ios::off_type last(-1);
if(last != -1)
std::cout.seekp(last, std::ios::beg);
last = std::cout.tellp();
std::cout << "Number " << i << std::endl;
}
);
This is untested on windows, but should work. What it does is detect if the file descriptor or is a tty. If it is then it just writes '\r' if the pos hasn't changed since last time it printed or a newline. If it isn't a newline, it seeks to the last place it was after it printed.
It behaves differently for files than for tty. For a file, if something outputs to the stream between prints then it can overwrite some or all of what was written even after newlines. For ttys it just overwrites the chars at the beginning of the current line.
Hope it helps ;) [It should work on Linux.]
// "\e[0K" Clear line from cursor to the end
cout << "\e[A\r\e[0K"<<what_you_want<<endl;
来源:https://stackoverflow.com/questions/3277058/how-to-rollback-lines-from-cout