DCの属性保存
属性を残す
これまで、デバイスコンテキストについて色々操作してきました
文字色の指定でわかるようにデバイスコンテキストはその属性を参照します
一般的にはWM_PAINTが発生した時など、HDCを取得してから
操作をはじめる時に設定すれば問題ありませんが
ある属性を永続的に残しておきたい場合もあることでしょう
一度デバイスコンテキストの属性を設定しても
ウィンドウプロシージャの終了時にそれは破棄されてしまいます
しかし、WNDCLASS構造体のstyleメンバにCS_OWNDCを指定すれば
デバイスコンテキストの属性が保存されます
これを利用すれば、WM_CREATE などが発生した時に
一度だけデバイスコンテキストの属性を指定するだけで
以降、デバイスコンテキストを取得した時の属性も全て影響されます
#include <windows.h>
LRESULT CALLBACK WndProc(HWND hwnd , UINT msg , WPARAM wp , LPARAM lp) {
HDC hdc;
PAINTSTRUCT ps;
LPCTSTR lptStr = TEXT("Kitty on your lap");
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_CREATE:
hdc = GetDC(hwnd);
SetTextColor(hdc , RGB(0xFF , 0 , 0));
ReleaseDC(hwnd , hdc);
return 0;
case WM_PAINT:
hdc = BeginPaint(hwnd , &ps);
TextOut(hdc , 10 , 10 , lptStr , lstrlen(lptStr));
EndPaint(hwnd , &ps);
return 0;
}
return DefWindowProc(hwnd , msg , wp , lp);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow ) {
HWND hwnd;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return -1;
hwnd = CreateWindow(
TEXT("KITTY") , TEXT("Kitty on your lap") ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , hInstance , NULL
);
if (hwnd == NULL) return -1;
while(GetMessage(&msg , NULL , 0 , 0)) DispatchMessage(&msg);
return msg.wParam;
}
このプログラムでは、WM_CREATE発生時に一度だけSetTextColor()を呼び出しています
デバイスコンテキストの属性は保存されるので、WM_PAINTで呼び出された時
デバイスコンテキストのテキストの色は赤色に設定されています
もう一つの方法として、WNDCLASS ではなく関数を用いる方法があります
一般的に、デバイスコンテキストの属性を保存する方法としてはこちらが推奨されます
デバイスコンテキストを保存する時は、まず SaveDC() 関数を用います
int SaveDC(HDC hdc);
hdc には、属性を保存するデバイスコンテキストのハンドルを指定します
関数が成功すると、このデバイスコンテキストの ID が、失敗すれば 0 が返ります
SaveDC() を用いれば、デバイスコンテキストをスタックに保存します
そのため、複数のデバイスコンテキストの状態を同時に保存できます
保存したデバイスコンテキストの情報を得るには RestoreDC() を使います
BOOL RestoreDC(HDC hdc , int nSavedDC);
hdc には属性を設定するデバイスコンテキストのハンドルを
nSavedDC は、正数を指定するとデバイスコンテキストの ID と判断され
その ID に対応したデバイスコンテキストを取得します
この ID は SaveDC() が返した値でなければなりません
負数 -n であれば、n 回前に SaveDC() で保存したデバイスコンテキストが取得されます
関数が成功すれば 0 以外、失敗すれば 0 が返ります
この関数は、スタックのトップから指定されたデバイスコンテキストまでの情報を削除します
CS_OWNDC と異なり、この方法は一時的な保存に適しています
例えば、関数で HDC を受け取り、何らかの描画処理をするために
デバイスコンテキストの属性を変更しなければならないということもあります
この時、属性を変更することに問題はありませんが
処理が呼び出し元に返る前に、属性の状態を元に戻しておかなければいけません
このような処理を行う時、SaveDC() を使って保存すれば最初の状態に復元できます
#include <windows.h>
#define TITLE TEXT("Kitty on your lap")
BOOL TextOutClr(HDC hdc , int x , int y , LPCTSTR str , COLORREF color) {
if (hdc == NULL) return FALSE;
SaveDC(hdc);
SetTextColor(hdc , color);
TextOut(hdc , x , y , str , lstrlen(str));
RestoreDC(hdc , -1);
return TRUE;
}
LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
HDC hdc;
PAINTSTRUCT ps;
int iHdcID;
TEXTMETRIC tm;
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
case WM_PAINT:
hdc = BeginPaint(hWnd , &ps);
GetTextMetrics(hdc , &tm);
TextOutClr(hdc , 0 , 0 , TITLE , RGB(0xFF , 0 , 0));
TextOut(hdc , 0 , tm.tmHeight , TITLE , lstrlen(TITLE));
EndPaint(hWnd , &ps);
return 0;
}
return DefWindowProc(hWnd , msg , wp , lp);
}
int WINAPI WinMain(HINSTANCE hInstance , HINSTANCE hPrevInstance ,
PSTR lpCmdLine , int nCmdShow) {
HWND hWnd;
MSG msg;
WNDCLASS winc;
winc.style = CS_HREDRAW | CS_VREDRAW;
winc.lpfnWndProc = WndProc;
winc.cbClsExtra = winc.cbWndExtra = 0;
winc.hInstance = hInstance;
winc.hIcon = LoadIcon(NULL , IDI_APPLICATION);
winc.hCursor = LoadCursor(NULL , IDC_ARROW);
winc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
winc.lpszMenuName = NULL;
winc.lpszClassName = TEXT("KITTY");
if (!RegisterClass(&winc)) return 1;
hWnd = CreateWindow(
TEXT("KITTY") , TITLE ,
WS_OVERLAPPEDWINDOW | WS_VISIBLE ,
CW_USEDEFAULT , CW_USEDEFAULT ,
CW_USEDEFAULT , CW_USEDEFAULT ,
NULL , NULL , hInstance , NULL
);
if (hWnd == NULL) return 1;
while (GetMessage(&msg , NULL , 0 , 0 )) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
return msg.wParam;
}
このプログラムで定義している TextOutClr() 関数は
最後の引数で描画する文字列の色を指定することができます
関数の内部でデバイスコンテキストの文字色を設定し TextOut() を用いて描画し
処理が呼び出し元に戻る前に RestoreDC() を用いて設定を元に戻します
SaveDC()
int SaveDC(HDC hdc);
デバイスコンテキストの状態を保存します
hdc - 保存するデバイスコンテキストを指定します
戻り値 - デバイスコンテキストの ID。失敗すると 0
RestoreDC()
BOOL RestoreDC(HDC hdc , int nSavedDC);
デバイスコンテキストの状態を SaveDC() で保存した状態に復元します
hdc - デバイスコンテキストを指定します
nSavedDC - デバイスコンテキストの ID、または負数でスタックの要素を指定します
戻り値 - 成功すると 0 以外。失敗すると 0