- Thread-safe
ProgressBar
andProgressSpinner
classes - Header-only library. Grab a copy of
include/indicators
- Source for the above GIF can be found here
- MIT License
To introduce a progress bar in your application, include indicators/progress_bar.hpp
and create a ProgressBar
object.
#include <indicators/progress_bar.hpp>
int main() {
indicators::ProgressBar bar;
return 0;
}
Here's the general structure of a progress bar:
<prefix_text> <bar_start> <fill> <lead> <remaining> <bar_end> <progress_percentage>? <postfix_text>
^^^^^^^^^^^^^^^^^^ Bar Width ^^^^^^^^^^^^^^^^^^ ^^^^^ Show/Hide ^^^^^
Each of these elements (and more) can be configured using the ProgressBar API. Here's an example configuration:
#include <indicators/progress_bar.hpp>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
return 0;
}
Now that the bar is configured, let's update the state of the bar. The amount of progress in ProgressBar is maintained as a float in range [0, 100]
. When progress reaches 100, the progression is complete.
From application-level code, there are two ways in which you can update this progress:
You can update the progress bar using bar.tick()
which increments progress by exactly 1%
.
#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
while (true) {
bar.tick();
if (bar.is_completed())
break;
std::this_thread::sleep_for(std::chrono::milliseconds(100));
}
return 0;
}
The above code will print a progress bar that goes from 0 to 100% at the rate of 1% every 100 ms.
If you'd rather control progress of the bar in discrete steps, consider using bar.set_progress(value)
. Example:
#include <indicators/progress_bar.hpp>
#include <thread>
#include <chrono>
int main() {
indicators::ProgressBar bar;
// Configure the bar
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("=");
bar.lead_bar_progress_with(">");
bar.fill_bar_remainder_with(" ");
bar.end_bar_with("]");
bar.set_postfix_text("Getting started");
bar.set_foreground_color(indicators::Color::GREEN);
// Update bar state
bar.set_progress(10); // 10% done
// do some work
std::this_thread::sleep_for(std::chrono::milliseconds(100));
bar.set_progress(30); // 30% done
// do some more work
std::this_thread::sleep_for(std::chrono::milliseconds(600));
bar.set_progress(65); // 65% done
// do final bit of work
std::this_thread::sleep_for(std::chrono::milliseconds(300));
bar.set_progress(100); // all done
return 0;
}
#include <indicators/progress_bar.hpp>
#include <vector>
int main() {
indicators::ProgressBar bar;
bar.set_bar_width(50);
bar.start_bar_with("[");
bar.fill_bar_progress_with("■");
bar.lead_bar_progress_with("■");
bar.fill_bar_remainder_with("-");
bar.end_bar_with("]");
bar.set_foreground_color(indicators::Color::YELLOW);
// As configured, the bar will look like this:
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70%
//
//
std::atomic<size_t> index{0};
std::vector<std::string> status_text =
{
"Rocket.exe is not responding",
"Finding a replacement engineer",
"Buying more snacks",
"Assimilating the modding community",
"Crossing fingers",
"Porting KSP to a Nokia 3310"
};
// Let's say you want to append some status text to the right of the progress bar
// You can use bar.set_postfix_text(...) to append text to the right
//
// [■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■■-------------] 70% Finding a replacement engineer
// ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
//
//
auto job = [&bar, &index, &status_text]() {
while (true) {
if (bar.is_completed()) {
break;
}
bar.set_postfix_text(status_text[index % status_text.size()]);
bar.tick();
index += 1;
std::this_thread::sleep_for(std::chrono::milliseconds(200));
}
};
std::thread first_job(job);
std::thread second_job(job);
std::thread third_job(job);
std::thread last_job(job);
first_job.join();
second_job.join();
third_job.join();
last_job.join();
return 0;
}
To introduce a progress spinner in your application, include indicators/progress_spinner.hpp
and create a ProgressSpinner
object.
#include <indicators/progress_spinner.hpp>
int main() {
indicators::ProgressSpinner spinner;
return 0;
}
Here's the general structure of a progress spinner:
<prefix_text> <spinner> <progress_percentage>? <postfix_text>
Each of these elements (and more) can be configured using the ProgressSpinner API. Here's an example configuration:
#include <indicators/progress_spinner.hpp>
int main() {
indicators::ProgressSpinner spinner;
// Configure the spinner
spinner.set_prefix_text(" ");
spinner.set_postfix_text("Checking credentials");
spinner.set_foreground_color(indicators::Color::YELLOW);
spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"});
// Update spinner state
return 0;
}
ProgressSpinner has a vector of strings: spinner_states
. At each update, the spinner will pick the next string from this sequence to print to the console. The spinner state can be updated similarly to ProgressBars: Using either tick()
or set_progress(value)
.
#include <indicators/progress_spinner.hpp>
int main() {
indicators::ProgressSpinner spinner;
// Configure the spinner
spinner.set_postfix_text("Checking credentials");
spinner.set_foreground_color(indicators::Color::YELLOW);
spinner.set_spinner_states({"⠈", "⠐", "⠠", "⢀", "⡀", "⠄", "⠂", "⠁"});
// Update spinner state
auto job = [&spinner]() {
while (true) {
if (spinner.is_completed()) {
spinner.set_foreground_color(indicators::Color::GREEN);
spinner.set_prefix_text("✔");
spinner.hide_spinner();
spinner.hide_percentage();
spinner.set_postfix_text("Authenticated!");
spinner.mark_as_completed();
break;
} else
spinner.tick();
std::this_thread::sleep_for(std::chrono::milliseconds(40));
}
};
std::thread thread(job);
thread.join();
return 0;
}
Contributions are welcome, have a look at the CONTRIBUTING.md document for more information.
The project is available under the MIT license.