2016. 1. 9.
石立 喬

Visual Studio Community 2015の使い方(7)

―― 水平と垂直のトラックバーを使用して色を作成する ――

 マウスでドラッグして数値を入力しいことがある。スクロールバーやトラックバーは、その目的で使用できる。
 ここでは、トラックバーを使用し、RGBやHSVの値を設定することにより、その色を表示する簡単なプログラムを紹介する。具体的には、R、G、B用の三個の水平トラックバーにより色を生成するプログラムと、H(Hue、色相)、S(Saturation、彩度)、V(Value、明度)用の三個の垂直トラックバーで色を作成するプログラムを紹介する。前者に水平トラックバーを使用し、後者に垂直トラックバーを使用したのに特別の意味はなく、ただ、両者を紹介したかったからである。

トラックバー(Track Bar)
 トラックバーは、チャンネルに沿って移動するスライダーと、刻み(ティックマーク)から成るコントロールウィンドウである。マウスでスライダーをドラッグしたり、左右のチャンネルをクリックしたりして、スライダーを移動できる。スライダーの位置を読み取ることにより、入力装置として使用できる。使用方法はアナログ的であるが、トラックバーの位置は、不連続な整数で表される。
 トラックバーには、水平と垂直の二種類あり、水平がデフォルトで、垂直の場合はTrack Bar StyleのTBS_VERTで指定する。
 水平トラックバーの場合は、左端が最小値、右端が最大値となり、垂直トラックバーは、上端が最小値、下端が最大値となる(これは日常感覚と異なるので、バグではないのかとの議論もされている)。テキスト入力ボックスなどに使われる垂直スクロールバーでは、下へ行くほど数字(桁番号の)が大きくなるが自然であるので、これと共通にした結果ではないかと思われる。CreateWindow関数で、システムクラス名をTRACKBAR_CLASSとして作成する(L"TRACKBAR"でないことに注意)。
 主なTrack Bar Styleには、
   TBS_HORZ ------------ 水平トラックバー、デフォルトなので、設定する必要はない
   TBS_VERT ------------ 垂直トラックバー
   TBS_AUTOTICKS ------ これを設定しないと、刻み(ティックマーク)が入らない
   TBS_NOTICKS --------- 刻みを入れない
   TBS_BOTH ----------- チャンネルの両側に刻みを入れる
がある。

トラックバー関連のメッセージ
 トラックバーとのやり取りに使用する主なTrack Bar Messageは、以下の通り。
   TBM_SETRANGE ------- wParamにはTRUEを、lParamにはMAKELONG(最小値、最大値)を入れる。
   TBM_SETTICFREQ ----- wParamには刻みtick markの周波数(何個置きか)を入れ、lParamは0にする。
   TBM_SETPOS --------- wParamにはTRUEを、lParamには設定したいlPosisionを入れる
   TBM_GETPOS --------- wParamとlParamに共に0を入れる。戻り値はスライダーの位置lPositionである。
 トラックバーに変更があったこと知らせるWindow Messageは、下記を使用する。
   WM_HSCROLL --------- 水平トラックバー用、wParamは使用しない。lParamからトラックバーへのハンドルが得られる。
   WM_VSCROLL --------- 垂直トラックバー用、wParamは使用しない。lParamからトラックバーへのハンドルが得られる。

RGB表色系とHSV表色系
 ブラウン管や液晶ディスプレイなど、三色の発光を合成するデバイスには、R(Red、赤)、G(Green、緑)、B(Blue、青)のRGB表色系が用いられる。これに対し、デザイナー側からは、H(Hue、色相)、S(Saturation、彩度)、V(Value、明度)で色を表現するHSV表色系が好まれる。HSV表色系と同じものにHSB系、似たものにHSL、HSIがある。
 RGB系からHSV系への変換、その逆変換のアルゴリズムは、多くの資料にあるが、「Visual C++ 2010 Expressを用いた易しい画像処理(3)」に述べてある。拙著「Visual C# 2013画像処理・数値プログラミング」で、High、Low、Up、Downの分かり易い表現を初めて使用した。
 ここでは、R、G、Bを水平トラックバーで与えて、その合成色を確認するプログラムと、H、S、Vを垂直トラックバーで与えて、それをRGB系に変換してから色を表示するプログラムの二種類を紹介する。

水平トラックバーを使ってRGBを設定し、色を確認するプログラム
 三個の水平トラックバーをマウスで操作し、色の要素であるRGBの値を、それぞれ0〜255の間で任意に設定すると、右側にRGBのそれぞれの値と、合成されてできた色が表示される。
 RGBの初期値は、中間値の127に設定しておく。
 親ウィンドウの背景色は、「使い方(4)」以降と同じ方法で設定した。
 プログラムは、下記から成っていて、すべてを、<プロジェクト名>.cppに記述する。
 1)親ウィンドウ上に、上から、R、G、Bの順に三個の水平トラックバーを配置する(図2)。
    TBS_AUTOTICKSは不可欠で、これがないと、刻みが付かない。
    各トラックバーは、TBM_SETRANGEで範囲を0〜255に設定し、TBM_SETTICFREQで刻みの頻度を1/16に設定し、
    TBM_SETPOSで初期値に設定する。
    それぞれ、ハンドルと識別子を関連付けておく。
 2)同様に、上記トラックバーの左に、三個のスタティックコントロールを配置し、「R」、「G」、「B」の文字を表示する(図2)。
 3)同様に、上記トラックバーの右に、三個のスタティックコントロールを配置し、R、G、Bの設定値を表示できるようにする(図2)。
    書き込みのために、ハンドルを設定しておく。初期値も設定しておく。
 4)「クリヤー」ボタンを作成し、識別子とハンドルを関連付けておく(図2)。
 5)設定した識別子、ハンドルを定義、宣言しておく(図1)。
   R、G、Bの値を入れる場所と初期値をグローバル化しておく。
 6)トラックバーの設定が変化した場合の処理を、case WM_HSCROLLに記述する(図3)。
   ・WM_HSCROLLと共に受け取ったlParamを、GetDlgID関数で、対応する識別子に変換する
   ・識別子に応じて、GetAndShowValue関数で、対応するトラックバーを読み取り、表示する
 7)「クリヤー」ボタンがクリックされた時の処理を、case IDC_BUTTON1に記述する(図4)。
   ・全てのトラックバーの設定を初期値に戻す
   ・全てのトラックバーを読み取って、表示する
   ・色を画面に表示するために、WM_PAINTを呼び出す
 8)case WM_PAINTに下記を記述する(図5)。
   ・RGBマクロで、RGB値からCOLORREF型の色を作成し、CreateSolodBrush関数で色ブラシを生成する
   ・SelectObject関数でブラシを設定する
   ・Rectangle関数で、矩形を塗りつぶす
 9)トラックバーのスライダー位置を読み取って値を表示する処理を、GetAndShowValue関数としてまとめる(図6)。

使用した関数とメッセージの説明
◎CreateWindowEx関数
 すでに、CreateWindow関数と共に解説してあるが、最近は、拡張機能を使用しなくても、CreateWindowEx関数を標準的に使用する傾向があるので、トラックバー作成に、これを使用した。最初の引数を0にしておけばよい。
 トラックバーを使用するときのクラス名は、TRACKBAR_CLASSを使用する。L"TRACKBAR_CLASS"ではないことに注意。
 ボタン作成にもCreateWindowEx関数を使用しており、こちらでは、拡張機能WS_EX_CLIENTEDGEを使用して、周辺を枠で囲んでいる。
◎GetDlgCtrlID関数
 コントロールのハンドルから、そのコントロールの識別子を返す関数で、引数はWWND型のハンドル、戻り値はint型の識別子である。
◎CreateSolidBrush関数
 特別のテクスチャを持たない、均一な面を塗りつぶすのに使用するブラシを生成する。引数は、COLORREF型の色、またはRGBマクロのRGB(r, g, b)を、直接用いる。
◎SelectObject関数
 ブラシを選択して、現時点の新しいブラシとする関数で、引数は、
   hdc -------- デバイスコンテキストへのハンドル
   hBrush ----- ブラシへのハンドル、実際には、CreateSolidBrush関数を直接記述することが多い。
である。戻り値は、それまでのブラシへのハンドルである。これは、元のブラシに戻す必要がある場合に使用する。
◎Rectangle関数
 塗りつぶしの四辺形を描く。周辺はその時点で設定されているペンで描かれ、内部はその時のブラシで塗りつぶされる。引数は、
   hdc ----------- デバイスコンテキストへのハンドル
   nLeftRect ------ 矩形の左辺のX座標
   nTopRect ------ 矩形の上辺のY座標
   nRightRect ----- 矩形の右辺のX座標
   nBottomRect --- 矩形の下辺のY座標
である。ペンが設定されていないときは、周辺が黒い枠で描かれる。


図1 最初の部分でトラックバーとボタンの識別子を設定し、ハンドルその他を宣言する



図2 InitInstanceで各種コントロールを作成し、ハンドルや識別子と関連づける



図3 WinProcに、各水平トラックバー変更のイベントに対する処理を記述する



図4 「クリヤー」ボタンに対しては、トラックバーを初期状態に設定し、結果を表示する



図5 WM_PAINTでは、RGBで指定した色で、矩形を塗りつぶす



図6 トラックバーからスライダー位置を読み取り、表示して、位置データを返す関数を作成する


得られた結果
 図7は、このプログラムの起動直後の画面で、図8は水平トラックバーでRGBを設定した一例である。


図7 起動直後は、RGBともに127nになっている



図8 水平トラックバーを使って色を作成した


垂直トラックバーを使ってHSVを設定し、色を確認するプログラム
 三個の垂直トラックバーをマウスで操作し、HSV表色系の値を任意に設定すると、右側にHSVのそれぞれの値と、合成されてできた色が表示される。Hの値は0〜360の実数、SとVのの値は0〜1の実数で、初期値は、H = 0、 S = 1、 V = 1としておく。
 プログラムは、下記から成っていて、すべてを、<プロジェクト名>.cppに記述する。水平トラックバーと同じ部分は、省略してある。
 1)親ウィンドウ上に、上から、R、G、Bの順に三個のトラックバーを配置する(図10)。
    各トラックバーは、TBM_SETRANGEで範囲を0〜100に設定し、TBM_SETTICFREQで刻みの頻度を1/10に設定し、
    TBM_SETPOSで初期値を、100、 0、 0の順に設定する。
    垂直トラックバーは、上から0、1、2、3 ・・・・・・ 100の順に位置が設定されているので、100が最下部、0が最上部を意味する。
 2)トラックバーの上に、三個のスタティックコントロールを配置し、「H」、「S」、「V」の文字を表示する(図10)。
 3)トラックバーの右に、三個のスタティックコントロールを配置して、HSV値の表示を可能にし、最初は初期値を表示する(図10)。
 4)「クリヤー」ボタンを作成する(図10)。
 5)設定した識別子、ハンドルを定義、宣言しておく(図9)。
   HSV値と色crColorを宣言し、初期値を与えておく。
 6)垂直トラックバーの設定が変化した場合の処理を、case WM_VSCROLLに記述する(図11)。
   ・後述するGetTrackValue関数を用いて、関連するトラックバーを読み取る(0〜1の範囲に変換されている)
   ・Hに対しては360倍し、SとVはそのままにしてHSV値とする。
 7)「クリヤー」ボタンがクリックされた時の処理を、case IDC_BUTTON1に記述する(図12)。
   ・H、S、Vの各トラックバーのスライダーを、100。 0、 0になるように設定する
   ・H、S、Vの初期値を表示する
   ・色crColorを赤に設定する
   ・WM_PAINTを呼び出して、色を表示する
 8)case WM_PAINTに、色の描画処理を記述する(図13)。
   その時に設定されているcrColorでブラシを作成し、矩形を塗りつぶす。
 9)トラックバーのスライダー位置を読み取り、0〜1の範囲に変換するGetAndShowValue関数を記述する(図6)。


図9 HSV値と色をグローバル変数として宣言し、初期設定しておく



図10 TBS_VERTで垂直トラックバーに変え、配置も変更する



図11 WM_HSCROLLをWM_VSCROLLに変え、各垂直トラックバー変更のイベントに対応する



図12 「クリヤー」ボタンに対しては、初期状態に戻し、表示する



図13 WM_PAINTを使って色を表示する



図14 トラックバーから読み取って位置から値へ変換する関数を作成する



図15 HSV値をRGB値に変換し、COLORREF型の色として返す関数を作成する


得られた結果
 
図16と図17は、このプログラムの起動直後の画面と、垂直トラックバーでHSVを設定した一例である。


図16 起動直後は、Hは0(赤)に、SとVはともに1.00になっている



図17 垂直トラックバーでHSVを設定した例










「Visual C++の勉強部屋」(目次)