在终端打印进度条原理很简单,有以下几点要清楚:
\r
的作用是将光标移回行首。
\n
的作用是换行(通常会 flush 缓冲的行)。
我们可以用 \r
将光标移回行首,重新打印一样格式的内容,覆盖旧的内容,由于机器运行速度非常快,看起来就像原地修改一样。
下面是我自己实现的一个简单的进度条类,不过只是实现功能,不保证 bug free。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58
| #include <cstdio> #include <ios> #include <iostream> #include <string> #include <sys/types.h> #include <unistd.h>
class ProgressBar { public: ProgressBar(const char finish = '#', const char unfini = '.') : _flags("-\\|/"), _finish(finish), _progress_str(100, unfini), _cur_progress(0) {}
void print_bar(const ushort n) { if (_cur_progress != 0 && n <= _cur_progress) { std::cerr << "\e[31merror\e[m: n(" << n << ") should > _cur_progress(" << _cur_progress << ")" << std::endl; return ; } for (ushort i = _cur_progress; i < n; i++) { _progress_str[i] = _finish; } _cur_progress = n; std::string f, p; if (n == 100) { f = "\e[1;32mOK\e[m"; p = "\e[1;32m100%\e[m"; } else { f = _flags[n % 4]; p = std::to_string(n) + '%'; } std::cout << std::unitbuf << '[' << f << ']' << '[' << _progress_str << ']' << '[' << p << "]" << '\r'; if (n >= 100) { std::cout << std::endl; } } private: std::string _flags; std::string _progress_str; ushort _cur_progress; char _finish; };
int main(int argc, char* argv[]) { ProgressBar pb; for (int i = 0; i <=100; i++) { pb.print_bar(i); usleep(50000); } return 0; }
|
输出: