SetBkModeで文字背景の描画方法を切り替える
Windows APIで文字列や図形を描画するとき、前景色だけを指定しても、文字の背後にある色の扱いまでは決まりません。GDIのデバイスコンテキスト(HDC)には背景モードがあり、SetBkModeを使うと、文字の背景を塗りつぶすか、既存の画面を残すかを切り替えられます。
この設定は、ラベル、ステータス表示、カスタムコントロール、印刷処理などで見た目を左右します。背景モードの値、背景色、描画順序を正しく理解しておくと、文字の周囲に四角い色が残る問題や、再描画時のちらつきを抑えやすくなります。
SetBkModeの役割と基本動作
SetBkModeの宣言は次の形式です。
int SetBkMode(
HDC hdc,
int mode
);
第1引数には対象となるデバイスコンテキスト、第2引数には背景モードを指定します。主な値はOPAQUEとTRANSPARENTです。OPAQUEでは文字の背景領域を現在の背景色で塗りつぶし、TRANSPARENTでは文字の形だけを描画して、下にある画像や図形を残します。
int oldMode = SetBkMode(hdc, TRANSPARENT);
SetTextColor(hdc, RGB(0, 0, 0));
TextOutW(hdc, 20, 20, L"状態: 実行中", 8);
SetBkMode(hdc, oldMode);
戻り値は、変更前の背景モードです。値が0の場合は失敗を示します。複数の描画処理を同じHDCで行う場合は、変更前の値を保存して最後に戻すと、呼び出し元や後続処理への影響を避けられます。画面表示の設計を調べる際には、豪州オンライン賭博の解説のように、情報量の多い画面で文字と背景がどう組み合わされるかを見る視点も役立ちます。
OPAQUEとTRANSPARENTの使い分け
OPAQUEは、文字の背後を一定色で消去してから文字を描くモードです。背景画像の上に文字を置く場合、文字領域だけが背景色で覆われるため、読みやすさを確保しやすい反面、矩形の境界が目立つことがあります。背景色はSetBkColorで設定します。
TRANSPARENTは、既存のピクセルを変更せずに文字を描画します。画像、グラデーション、模様付きの領域に自然に文字を重ねたい場合に適しています。ただし、背景とのコントラストが不足すると文字が見えにくくなり、前回の文字を消さずに同じ位置へ再描画すると残像が発生する場合があります。
背景モードは文字色を指定するSetTextColorとは別の設定です。また、文字列の外側に塗りつぶし領域を作るかどうかを決めるものであり、ウィンドウ全体の背景消去や再描画を自動的に制御するものではありません。WM_ERASEBKGNDや無効領域の処理とは分けて考える必要があります。
API宣言と描画結果の確認
GDI関数を使うときは、対象のHDCが有効な期間にSetBkModeを呼び出します。BeginPaintで取得したHDC、GetDCで得たHDC、プリンター用HDCなど、描画対象によって背景の見え方が変わるため、画面と印刷結果を同じものとして扱わないことが重要です。
| 設定 | 背景の処理 | 適した用途 | 注意点 |
|---|---|---|---|
OPAQUE |
背景色で文字領域を塗りつぶす | 単色背景、表示の消去を兼ねた描画 | 矩形の境界が見えることがある |
TRANSPARENT |
下にあるピクセルを残す | 画像や模様への文字重ね | コントラスト不足や残像に注意 |
SetBkColor併用 |
OPAQUEの塗りつぶし色を指定 |
識別しやすいラベル表示 | モードだけでは色は変わらない |
SetTextColor併用 |
文字そのものの色を指定 | 背景との視認性調整 | 背景処理とは別の設定 |
テキスト描画関数によっては、追加フラグが結果に影響します。たとえばExtTextOutではETO_OPAQUEを指定すると、背景モードとは別に文字列の背景矩形を塗りつぶせます。DrawTextを使う場合も、背景消去の責任がウィンドウ側にあるのか、描画関数側にあるのかを確認してください。
戻り値の検査も実装上の基本です。失敗時の原因調査では、HDCがNULLになっていないか、描画対象が破棄されていないか、API呼び出し直前に別の処理がデバイスコンテキストの状態を変更していないかを確認します。関連するAPI資料はWindows API資料の入口から整理して参照できます。
設定時に確認したい項目
画面の一部だけを更新する処理では、背景モードを変更したこと自体より、変更後のHDC状態をどこまで管理するかが重要です。次の点を先に決めておくと、表示の不具合を切り分けやすくなります。
- 変更前の背景モードを戻り値で保存する
SetBkColorとSetTextColorを別々に確認する- 文字列の再描画前に古い表示を消す
- 背景画像と文字のコントラストを確認する
TextOutとExtTextOutの追加指定を比較する- HDCの有効範囲を
BeginPaintやReleaseDCと合わせる
特にカスタムコントロールでは、描画イベントが発生するたびにHDCの状態が初期化されるとは限りません。親ウィンドウや別の描画関数が設定した背景色、マッピングモード、クリッピング領域が残っていることもあるため、必要な状態を明示的に設定するほうが安全です。
ちらつき対策としては、メモリ上の互換ビットマップへ描画してから画面へ転送するダブルバッファリングも有効です。ただし、ダブルバッファリングを導入しても、背景モードの選択が不適切なら文字の周囲に不要な矩形が現れます。
描画結果を安定させる実装手順
実際のプログラムでは、文字を描く直前に必要な状態を設定し、処理終了後に元へ戻す流れを作ります。複数の描画関数が同じHDCを共有する場合ほど、状態の保存と復元が重要になります。
- HDCを取得した直後に対象を確認する
- 背景モードを用途に応じて明示する
- 背景色と文字色を同じ描画単位で設定する
- 描画後に保存したモードへ戻す
- ウィンドウのサイズ変更と再描画で結果を確認する
TRANSPARENTを使うなら、文字の下にある背景が毎回正しく再描画される設計にします。OPAQUEを使うなら、文字列の長さやフォント変更によって塗りつぶし範囲が不足しないかを確認します。文字列を短く更新するケースでは、以前の長い文字が残るため、無効領域の再描画や背景の消去も必要です。
まず検証用の小さなウィンドウを作り、同じ背景画像の上へOPAQUEとTRANSPARENTで同じ文字列を描画し、SetBkColorと戻り値の変化を確認してください。