ViVi Home > 技術文書 > さくさく理解できる C/C++ コンソールアプリ入門 > 文字表示色指定(Win32)
コンソールアプリは文字しか表示出来ないので、どうしても表現力が不足する。
通常、文字・背景色は固定だが、それらを変更可能にすれば、それなりに表現力が向上し、アプリの自由度が増す。
本稿では、コンソールアプリの文字・背景色を指定する関数を Wind32 API を使って定義する。
この関数を使えば、下図のように画面をカラフルにすることができるぞ。
// 色定義 #define COL_BLACK 0x00 #define COL_DARK_BLUE 0x01 #define COL_DARK_GREEN 0x02 #define COL_DARK_CYAN 0x03 #define COL_DARK_RED 0x04 #define COL_DARK_VIOLET0x05 #define COL_DARK_YELLOW 0x06 #define COL_GRAY 0x07 #define COL_LIGHT_GRAY 0x08 #define COL_BLUE 0x09 #define COL_GREEN 0x0a #define COL_CYAN 0x0b #define COL_RED 0x0c #define COL_VIOLET 0x0d #define COL_YELLOW 0x0e #define COL_WHITE 0x0f #define COL_INTENSITY 0x08 // 高輝度マスク #define COL_RED_MASK 0x04 // 赤色ビット #define COL_GREEN_MASK 0x02 // 緑色ビット #define COL_BLUE_MASK 0x01 // 青色ビット
まずは色名を上記のように定義する。
本稿では Win32 を使って色指定関数を定義する。なので、当然ながら Windows 環境でのみ利用可能である。
だが、その関数をコールする側は Win32 とは関係無いようにしておきたい。
そうしておけば、プログラムを他の環境に移植するとき、色指定関数のみを新しい環境用に書き換えるだけで、
色指定関数を呼び出す本体部分をいっさい変更しなくても済み、移植コストが大幅に削減できるからだ。
COL_INTENSITY からの最後の4つは色名ではなく、色の輝度、RGBを表すマスクビットだ。
色は2進数の RGB の組み合わせで表される。赤は 0x04、緑は 0x02、青は 0x01 だ。
これらを組み合わせて8種類の色が作られる。例えば、赤と青を混ぜると 0x04 | 0x01 = 0x05 で紫となる。
※ | はビット毎の OR 演算を表す。2進数、16進数がよくわからない人はここを読んで勉強してね。
// 文字色指定 for Windows Console void setColor(int col) { HANDLE hCons = GetStdHandle( STD_OUTPUT_HANDLE ); // コンソールハンドル取得 WORD attr = 0; // API に渡すアトリビュート if( col & COL_INTENSITY ) // 高輝度ビットが立っていれば attr |= FOREGROUND_INTENSITY; // アトリビュートの高輝度ビットを立てる if( col & COL_RED_MASK ) attr |= FOREGROUND_RED; if( col & COL_GREEN_MASK ) attr |= FOREGROUND_GREEN; if( col & COL_BLUE_MASK ) attr |= FOREGROUND_BLUE; SetConsoleTextAttribute(hCons, attr); // 色指定 }
上記が色設定を行う setColor(int col) 関数の定義だ。
引数で渡す色は先に定義した COL_GREEN などを指定する。
Win32 コンソールでは、Win32 API の SetConsoleTextAttribute(HANDLE, WORD) を利用して色を設定することができる。
最初の引数はコンソールを表すハンドルで、GetStdHandle( STD_OUTPUT_HANDLE ) をコールすると取得できる。
なお、Win32 API を利用するには、#include <windows.h> が必要なので、ソースの最初の方に記述するのを忘れないように。
もしかしたら、何を言ってるのかさっぱりわからないかもしれないが、深い理解は大変なので、当面はそいうお約束だとご理解いただきたい。
文字色そのものは SetConsoleTextAttribute() の第2引数で指定する。
この値は FOREGROUND_INTENSITY、FOREGROUND_RED、FOREGROUND_GREEN、FOREGROUND_BLUE の組み合わせでしている。
引数の col の方は値を独自に定義したので、それぞれのビットを調べ、FOREGROUND_XXX の組み合わせに変換している。
色指定の変換ができたら、それを SetConsoleTextAttribute() に渡せば、色指定の完了だ。
※ if( col & XXX ) は col の XXX ビットを調べ、ビットが立っていれば真となる。if( (col & XXX) != 0 ) と書いても良い。
ビットの値を調べるのは非常によく使うテクニックなので、ぜひ覚えていただきたい。
void setColor(int fg, int bg) { HANDLE hCons = GetStdHandle( STD_OUTPUT_HANDLE ); WORD attr = 0; if( fg & COL_INTENSITY ) attr |= FOREGROUND_INTENSITY; if( fg & COL_RED_MASK ) attr |= FOREGROUND_RED; if( fg & COL_GREEN_MASK ) attr |= FOREGROUND_GREEN; if( fg & COL_BLUE_MASK ) attr |= FOREGROUND_BLUE; if( bg & COL_INTENSITY ) attr |= BACKGROUND_INTENSITY; if( bg & COL_RED_MASK ) attr |= BACKGROUND_RED; if( bg & COL_GREEN_MASK ) attr |= BACKGROUND_GREEN; if( bg & COL_BLUE_MASK ) attr |= BACKGROUND_BLUE; SetConsoleTextAttribute(hCons, attr); }
上記の関数は、文字色指定だけでなく、第2引数で背景色も指定可能な関数だ。
第1引数の文字色の処理は前と同じで、第2引数の背景色の処理が追加されている。
文字色の場合と同じように、強調・RGBビットを調べ、SetConsoleTextAttribute() へ渡す attr を構築し、
SetConsoleTextAttribute() をコールしているだけだ。
背景色は、BACKGROUND_INTENSITY、BACKGROUND_RED、BACKGROUND_GREEN、BACKGROUND_BLUE の組み合わせとなる。
このページの最初のスクリーンショットの様に、背景を指定し、各色のテキストを表示するサンプルです。
#include <iostream> #include <Windows.h> using namespace std; int main() { setColor(COL_WHITE);cout << "whilte\t"; setColor(COL_CYAN); cout << "cyan\t"; setColor(COL_YELLOW); cout << "yellow\t"; setColor(COL_VIOLET); cout << "violet\t"; setColor(COL_GREEN);cout << "green\t"; setColor(COL_RED);cout << "red\t"; setColor(COL_BLUE); cout << "blue\t"; cout << "\n"; setColor(COL_WHITE, COL_BLACK); cout << "BG: dark-blue\t"; setColor(COL_WHITE, COL_DARK_BLUE); cout << "whilte\t"; setColor(COL_CYAN, COL_DARK_BLUE); cout << "cyan\t"; setColor(COL_YELLOW, COL_DARK_BLUE);cout << "yellow\t"; setColor(COL_VIOLET, COL_DARK_BLUE); cout << "violet\t"; setColor(COL_GREEN, COL_DARK_BLUE); cout << "green\t"; setColor(COL_RED, COL_DARK_BLUE); cout << "red\t"; setColor(COL_BLUE, COL_DARK_BLUE);cout << "blue\t"; cout << "\n"; getchar(); return 0; }
演習問題