ViVi Home > 技術文書 > さくさく理解できる C/C++ コンソールアプリ入門 > 文字表示色指定(Win32)


 

 

文字表示色指定(Win32)
Copyright (C) 2014 by Nobuhide Tsuda

概要

コンソールアプリは文字しか表示出来ないので、どうしても表現力が不足する。
通常、文字・背景色は固定だが、それらを変更可能にすれば、それなりに表現力が向上し、アプリの自由度が増す。

本稿では、コンソールアプリの文字・背景色を指定する関数を 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;
}

演習問題

  1. 1文字ずつ文字色、背景色をランダムに指定し、画面を "*" で埋め尽くすプログラムを書きなさい。