デバイスコンテキストについて

業務にて、デバイスコンテキストを使っての描画処理を担当。
描画関係の知識がなかったのでちょろっと勉強してみたので、メモを残しておく(たいしたことないけど 笑)。

Ⅰ. デバイスコンテキストとは

ウィンドウの描画に必要な材料のパッケージ。よく画用紙と画材のセットと表現される。
文字を書いたり、背景の色を変えたり、線を引いたり、画像を表示させたり・・・
といった全ての操作はこいつ(デバイスコンテキスト)のハンドルを取得するところから始まる。

業務系アプリでは、画面のほぼ全てが MFC 標準のコントロールで事足りてしまうのであまり関わる機会がない。
が、色の変更などの細かい制御をするときは世話になるので、覚えておくと非常に便利だ。

Ⅱ. 画用紙と画材のセット・・・というと?

デバイスコンテキストが画用紙と画材のセットと表現される理由は何か。
それは、デバイスコンテキストが持っているオブジェクトを知れば納得がいく。
以下がデバイスコンテキストが持つオブジェクト・・・つまり画材のリスト ( 厳密にはこれだけではない )

  • Bitmap ・・・ 画像(画像を表示するときに使う)
  • Brush  ・・・ ブラシ(背景を塗りつぶすときに使う)
  • Font   ・・・ フォント(文字を書くときに使う)
  • Pen     ・・・ ペン(線を引くときに使う)
  • Region   ・・・ 領域(描画領域を限定するときに使う)

デバイスコンテキストは、これらの画材を全種類持っている。
ただし、もてる画材は1種類につき1つで、Pen なら Pen 1個。
つまり、赤ペンに青ペンに緑も・・のように、同じ種類の画材は複数持てないので入れ替えて使う。

また、1つのウィンドウにつき、デバイスコンテキストは1つである。
ということから、ウィンドウ、およびそれに張り付いている全てのコントロールもウィンドウなので、それぞれが1つづつデバイスコンテキストを持っていることになる。

[デバイスコンテキストのイメージ ( クリックで最大化 )]
無題

Ⅲ. デバイスコンテキストの使い方

Ⅱ まででデバイスコンテキスト(以下 DC )の考え方が理解できたとうことで、実際にコードを書いてみる。
まずは、DC のハンドルを取得してから描画をおこなう一連の流れはこうだ。

  1. DC のハンドルを取得
  2. 画材を作成
  3. 画材を設定
  4. 描画
  5. 画材を元に戻す
  6. 画材を削除
  7. DC のハンドルを開放

すでにお気づきだと思うが、これにはいくつか注意点がある。

  • DC のハンドルを取得したら、最後に必ず開放すること
  • 使う画材を作成したら、最後に必ず削除すること
  • 画材を入れ替えたら、最後にかならず元に戻すこと

以上の点に注意して、画面(画用紙)を赤で塗りつぶす処理を書くとこうなる。

--------------------------------------------------------------------------------
// ※ hWnd は、描画対象となるウィンドウのハンドル

//
// 画面を赤で塗りつぶす
//

// DC のハンドルを取得
HDC hDC = ::GetDC( hWnd );

// 赤のブラシを作成(画材を作成)
HGDIOBJ hBrushRed = ::CreateSolidBrush( RGB( 255, 0, 0 ) );

// 赤のブラシを設定(画材を設定)
HGDIOBJ hBrushOld = ::SelectObject( hDC, hBrushRed );

// 画面をぬりつぶす(描画)
RECT rtWindow;
::GetWindowRect( hWnd, &rtWindow );
::PatBlt( hDC, 0, 0, rtWindow.right, rtWindow.bottom, PATCOPY );

// 画材を元に戻す
::SelectObject( hDC, hBrushOld );

// 画材を削除
::DeleteObject( hBrushOld );

// DC のハンドルを開放
::ReleaseDC( hWnd, hDC );

--------------------------------------------------------------------------------

これで、画面を赤で塗りつぶすことができた。

やりたい描画、つまり使う画材によって呼び出す API が変わるが、
基本的な処理の流れは、どの画材を使うときも同じである。
( 逆に、それぐらいしか変わりがないとも言える )

Ⅳ. 最後に

今回は、GetDC を使って実装してみた。
GetDC は、ウィンドウハンドルのパラメータに NULL を設定すると、スクリーン全体の DC をも取得できる強力な API である。
画面のちょっとした描画にはもっと適した BeginPaint という API があるし、MFC のクラスを使うともっと簡単に実装できるので、
次回はそれらを使ったコードの書いてみることにする。

 

以上。