プログレスバーを表示するC++ライブラリを作った
成果物:
背景
Pythonで重い処理をする際は、tqdmでプログレスバーを表示している。最近、C++でもプログレスバーを表示させたいと思ったのだが、既存のライブラリは微妙なものしかなかった。サーベイの結果は以下の通り。
- tqdm.cpp: tqdmのC++への公式ポートだがメンテされていない。コンパイルして動かしてみても正常に表示されない。
- indicators: スター数的には一番人気のライブラリ。だが、Windows + PowerShellの環境だと、バーの後に余分な改行が入り表示が乱れる。また、UTF8対応を謡ってはいるが、日本語環境では文字化けする。Win32 APIを使って文字出力していないことが原因と思われる。将来的に廃止予定のcodecvtクラスを使っているのも微妙に感じた。
- progressbar: 200行弱のシンプルなライブラリ。これでもよかったのだが、実行中の警告メッセージを表示させる機能がないのが気になった。
pbar
このように、自分好みのプログレスバーC++ライブラリがなかったので自作したのが、最初のpbarライブラリだ。バーの表示の形式はtqdmとほぼ同様である。進捗はUnicode文字"█"で表示しているが、WindowsではWriteConsoleW関数でターミナルに表示しているため、文字化けしない。最初のgif動画のように、複数のバーの同時表示にも対応している。設定しなければ、コンソールの横幅めいっぱいにバーを表示する。なお、本ライブラリはスレッドセーフではないので、バーのアップデートは同期的に行う必要がある。
サンプルは下記の通り。pbar::pbarクラスを作成した後、bar.init()
で進捗0%のバーを表示する。ループの終わりでbar++
としてバーの表示を更新する。bar.tick()
でもよい。
バーを複数表示する場合は、一番上のバー以外にenable_stack()
を設定する。
その他いくつか設定はあるが、名前からわかるだろう(説明放棄)。
#include <chrono> #include <iostream> #include <pbar.hpp> #include <thread> int main(void) { using namespace std::this_thread; using namespace std::chrono; constexpr auto total_ = 100; constexpr auto ncols = 100; pbar::pbar bar(total_, ncols); bar.set_description("[TASK0]"); bar.init(); // not always necessary bar.enable_recalc_console_width(1); // check console width every 10 ticks for (std::int64_t i = 0; i < total_; ++i, ++bar) { sleep_for(milliseconds(100)); } std::cout << "done!" << std::endl; pbar::pbar bar1(4); pbar::pbar bar2(8); pbar::pbar bar3(16); bar1.set_description("[TASK1]"); bar2.set_description("[TASK2]"); bar3.set_description("[TASK3]"); bar2.enable_stack(); bar3.enable_stack(); bar1.enable_recalc_console_width(10); // check console width every 10 ticks bar1.init(); for (auto i = 0; i < 4; ++i, ++bar1) { bar2.init(); for (auto j = 0; j < 8; ++j, ++bar2) { bar3.init(); for (auto k = 0; k < 16; ++k, ++bar3) { sleep_for(milliseconds(10)); } sleep_for(milliseconds(50)); } sleep_for(milliseconds(100)); } std::cout << "done!" << std::endl; return 0; }
210823_追記
スピナーも作った。サンプルプログラムはgithubを参照のこと。