やりたいこと
別に立派なGUIが作りたいんじゃない。作りたいのは、コンソールアプリで十分だ。
しかし、そのコンソールアプリが常に何かを出力し続けていたら?ちょっとモード変更したいとか、そのための入力処理を作るのも億劫だし、そもそも流れ続けるコンソールに入力したくもない。だが、コンソールアプリで十分なのに、画面なんて作りたくない。
これって、タスクトレイにボタン一つ置ければ、話は簡単じゃないか。
しかし、そんなことをC++でやろうとすると、途端に非常に面倒くさいことが要求される。Windowsならメッセージを受け取る為の見えないウィンドウを作り、Shell_NotifyIconでNOTIFYICONDATAを登録し…。
違う。違うんだ、私がやりたいのはそんなことじゃないんだ。ボタン押したら対応するイベントハンドラが発火して、後はチェックボックスぐらいがあれば、それで良いんだ。
zserge/tray
WINAPIを叩いたとしても、まぁ、数百行あればかけるっちゃかけるだろう。
でも私はWin APIを叩きたくないのだ。何故なら私はGUIを作りたい訳じゃないからだ。そこは本質ではないのだ。情けないことを言えば、ぶっちゃけWinAPIは得意ではないのだ。
かといって、コンソールアプリを作ってるのに、Qtの出る幕は無い。
というわけで、今回紹介するzserge/trayを使います。
C++でタスクトレイに格納したアプリケーションを、ヘッダファイル1つをインクルードするだけで簡単に作れてしまうライブラリ。リンクは不要。しかもクラスプラットフォームだ。
私はC++で使ったが、Cでも使える。(というか、C用だから、C++用も欲しいな)
サンプルコード
永遠と「Hoge Hoge」と言い続けるが、タスクトレイから「Piyo Piyo」モードに変更も出来て、終了も出来るプログラムの例を示す。これだけで、もう何となく使うことが出来ると思う。
//↓ OS設定。LinuxならTRAY_APPINDICATOR、MacならTRAY_APPKIT。Makefileに書いとくといい。 #define TRAY_WINAPI 1 #include "tray.h" #include <iostream> #include <thread> #include <chrono> using namespace std; using namespace std::chrono; volatile bool piyoMode; //!< Piyo Piyoとコンソールに出力するモード volatile bool processDone; //!< 処理完了フラグ void piyo(tray_menu *); //!< Piyoモードのトグル void finish(tray_menu *); //!< 終了処理 void _main(); //!< Hoge Hogeと出力するメイン処理 tray tray ={ //!< タスクトレイの設定 (char*)"icon.png", // タスクトレイのアイコン画像。別途用意しておく。 (tray_menu[]){ {(char*)"piyoMode",0,0,piyo}, //サブメニューを指定すれば、階層化も可能 {(char*)"-"}, // セパレータ {(char*)"exit",0,0,finish}, //終了 {nullptr} //最後の要素。必須。 } }; int main(int argc, char *argv[]){ piyoMode=processDone=false; thread t(_main);// 表示処理は別スレッド化 tray_init(&tray); //タスクトレイに登録 while(tray_loop(1) == 0); //タスクトレイが表示されている間ループ t.join(); return 0; } void piyo(tray_menu * item){ bool b =!item->checked; piyoMode = b; item->checked = b; //チェックボックスの表示非表示変更 tray_update(&tray); //更新 } void finish(tray_menu *){ processDone=true; tray_exit(); // タスクトレイから削除 } void _main(){ while(!processDone){ cout << (piyoMode? "Piyo Piyo" : "Hoge Hoge") << endl; // piyoかhogeを出力 this_thread::sleep_for(seconds(2)); } cout << "Done"<<endl; }
tray構造体
タスクトレイの情報。メニューとアイコンを設定する。Windowsでもアイコンってpngでいけるんやね。
static tray tray ={ (char*)"icon.png", (tray_menu[]){ {nullptr} //最後の要素。必須。 } };
tray_menu構造体
タスクトレイのメニュー。入れ子構造に出来たり、Check、Disable/Enableも設定出来る。textが"-"だとセパレータになる。
要素 | 説明 |
---|---|
char* text | メニュー名。"-"だとセパレータ |
int disabled | 有効無効の設定 |
int checked | チェックの設定 |
void (*cb)(struct tray_menu*) | コールバック関数。 |
void *context | お好きな様にお使い下さい。 |
tray_menu* submenu | サブメニュー |
関数
- tray_init(tray*): 初期化する。1が返ると失敗
- tray_update(tray*): disabledとか、checkedとかを変更した時に呼び出して、画面を更新
- tray_loop(int) : UIのループ。引数はブロッキングするかどうか。tray_exitが呼ばれると1が返る。
- tray_exit() : UIループを終了する