progressBar.hpp:
#ifndef __PROGRESSBAR_HPP
#define __PROGRESSBAR_HPP
#include <iostream>
#include <stdexcept>
#include <string>
// the following are UBUNTU/LINUX ONLY terminal color codes.
#define RESET "\033[0m"
#define BLACK "\033[30m" /* Black */
#define RED "\033[31m" /* Red */
#define GREEN "\033[32m" /* Green */
#define YELLOW "\033[33m" /* Yellow */
#define BLUE "\033[34m" /* Blue */
#define MAGENTA "\033[35m" /* Magenta */
#define CYAN "\033[36m" /* Cyan */
#define WHITE "\033[37m" /* White */
#define BOLDBLACK "\033[1m\033[30m" /* Bold Black */
#define BOLDRED "\033[1m\033[31m" /* Bold Red */
#define BOLDGREEN "\033[1m\033[32m" /* Bold Green */
#define BOLDYELLOW "\033[1m\033[33m" /* Bold Yellow */
#define BOLDBLUE "\033[1m\033[34m" /* Bold Blue */
#define BOLDMAGENTA "\033[1m\033[35m" /* Bold Magenta */
#define BOLDCYAN "\033[1m\033[36m" /* Bold Cyan */
#define BOLDWHITE "\033[1m\033[37m" /* Bold White */
class progressbar {
public:
// default destructor
~progressbar() = default;
// delete everything else
progressbar(progressbar const&) = delete;
progressbar& operator=(progressbar const&) = delete;
progressbar(progressbar&&) = delete;
progressbar& operator=(progressbar&&) = delete;
// default constructor, must call set_niter later
progressbar();
progressbar(const std::string& type, int n, bool showbar = true);
// reset bar to use it again
void reset();
// set number of loop iterations
void set_niter(int iter);
// chose your style
void set_done_char(const std::string& sym) { done_char = sym; }
void set_todo_char(const std::string& sym) { todo_char = sym; }
void set_opening_bracket_char(const std::string& sym) { opening_bracket_char = sym; }
void set_closing_bracket_char(const std::string& sym) { closing_bracket_char = sym; }
// to show only the percentage
void show_bar(bool flag = true) { do_show_bar = flag; }
// main function
void update();
void update(int n);
// default style
void setDefaultStyle();
private:
std::string m_type;
int progress;
int n_cycles;
int last_perc;
bool do_show_bar;
bool update_is_called;
std::string done_char;
std::string todo_char;
std::string opening_bracket_char;
std::string closing_bracket_char;
};
progressbar::progressbar()
: progress(0),
m_type(GREEN),
n_cycles(0),
last_perc(0),
do_show_bar(true),
update_is_called(false),
done_char("#"),
todo_char(" "),
opening_bracket_char("["),
closing_bracket_char("]") {}
progressbar::progressbar(const std::string& type, int n, bool showbar)
: progress(0),
m_type(type),
n_cycles(n),
last_perc(0),
do_show_bar(showbar),
update_is_called(false),
done_char("#"),
todo_char(" "),
opening_bracket_char("["),
closing_bracket_char("]") {}
void progressbar::reset() {
progress = 0, update_is_called = false;
last_perc = 0;
return;
}
void progressbar::set_niter(int niter) {
if (niter <= 0)
throw std::invalid_argument("progressbar::set_niter: number of iterations null or negative");
n_cycles = niter;
return;
}
void progressbar::update() {
if (n_cycles == 0)
throw std::runtime_error("progressbar::update: number of cycles not set");
if (!update_is_called) {
if (do_show_bar == true) {
std::cout << m_type << ":" << opening_bracket_char;
for (int _ = 0; _ < 50; _++)
std::cout << todo_char;
std::cout << closing_bracket_char << " 0%";
} else
std::cout << "0%";
}
update_is_called = true;
// compute percentage, if did not change, do nothing and return
int perc = progress * 100. / (n_cycles - 1);
if (perc < last_perc)
return;
// update percentage each unit
if (perc == last_perc + 1) {
// erase the correct number of characters
if (perc <= 10)
std::cout << "\b\b" << perc << '%';
else if (perc > 10 and perc < 100)
std::cout << "\b\b\b" << perc << '%';
else if (perc == 100)
std::cout << "\b\b\b" << perc << '%';
}
if (do_show_bar == true) {
// update bar every ten units
if (perc % 2 == 0) {
// erase closing bracket
std::cout << std::string(closing_bracket_char.size(), '\b');
// erase trailing percentage characters
if (perc < 10)
std::cout << "\b\b\b";
else if (perc >= 10 && perc < 100)
std::cout << "\b\b\b\b";
else if (perc == 100)
std::cout << "\b\b\b\b\b";
// erase 'todo_char'
for (int j = 0; j < 50 - (perc - 1) / 2; ++j) {
std::cout << std::string(todo_char.size(), '\b');
}
// add one additional 'done_char'
if (perc == 0)
std::cout << todo_char;
else
std::cout << done_char;
// refill with 'todo_char'
for (int j = 0; j < 50 - (perc - 1) / 2 - 1; ++j)
std::cout << todo_char;
// readd trailing percentage characters
std::cout << closing_bracket_char << ' ' << perc << '%';
if (perc == 100)
std::cout << std::endl;
}
}
last_perc = perc;
++progress;
std::cout << std::flush;
return;
}
void progressbar::update(int n) {
for (int i = 0; i < n; i++) {
update();
}
}
void progressbar::setDefaultStyle() {
set_todo_char(" ");
set_done_char("*");
set_opening_bracket_char("[");
set_closing_bracket_char("]");
}
#endif
测试代码test.cpp:
#include <unistd.h>
#include "progressbar.hpp"
int main(int argc, char* argv[]) {
progressbar bar;
bar.set_niter(60);
bar.setDefaultStyle();
for (size_t i = 0; i < 60; i++) {
// if ((i % 20) == 0) {
// bar.reset();
// }
bar.update();
sleep(1);
}
return 0;
}
编译:g++ ./test.cpp -o main, 运行./main, 结果输出:
还有点小问题是:输出*不连续,暂时未发现问题在哪里,待修改。