|
皆さんお待ちかねの(?) 先にことわっておきます まず、Win32APIの描画の概念図から 真ん中のHDCというのは、デバイスコンテキストのハンドル(ポインタ)です ・HPENはペンのハンドルです。 ・HBITMAPはビットマップのハンドルです。 ・HBRUSHはブラシのハンドルです。 ・HFONTはフォントのハンドルです。 ・HRGNはリージョンのハンドルです。 ・HPALETTEはパレットのハンドルです。 デバイスコンテキストには関連付けられた描画オブジェクトが必ず1種類ずつ存在します 今回のソースコードです。 //------------------------------------------------------//
// ウィンドウ描画メッセージ処理
//
// 引数: hWnd ウィンドウハンドル
//------------------------------------------------------//
void OnPaint(HWND hWnd){
// 描画開始
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
// ペン作成
HPEN hPen = CreatePen(PS_SOLID,5,RGB(255,0,0));
HPEN hNullPen = CreatePen(PS_NULL,1,RGB(0,0,0));
HPEN hDefPen = (HPEN)SelectObject(hdc,hPen);
// ブラシ作成
HBRUSH hBrush = CreateSolidBrush(RGB(0,255,0));
HBRUSH hDefBrush = (HBRUSH)SelectObject(hdc,hBrush);
// ビットマップ読み込み
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL); // インスタンスハンドル取得
HBITMAP hBmp = (HBITMAP)LoadImage(hInstance,_T("test.bmp"),IMAGE_BITMAP,0,0,LR_DEFAULTCOLOR | LR_SHARED | LR_LOADFROMFILE);
BITMAP Bmp;
GetObject(hBmp,sizeof(BITMAP),&Bmp);
HDC hBmpDC = CreateCompatibleDC(hdc);
HBITMAP hDefBmp = (HBITMAP)SelectObject(hBmpDC, hBmp);
// フォント作成
LOGFONT logfont = {};
logfont.lfHeight = 30; // 文字高さ
logfont.lfWidth = 12; // 文字幅
logfont.lfEscapement = 30; // 文字送りの方向とX軸の角度
logfont.lfOrientation = logfont.lfEscapement; // ベースラインとX軸との角度
logfont.lfWeight = FW_BOLD; // フォントの太さ
logfont.lfItalic = TRUE; // イタリック体指定
logfont.lfUnderline = TRUE; // 下線付き指定
logfont.lfStrikeOut = TRUE; // 打ち消し線指定
logfont.lfCharSet = SHIFTJIS_CHARSET; // キャラクタセット
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; // 出力精度
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; // クリッピングの精度
logfont.lfQuality = DEFAULT_QUALITY; // 出力品質
logfont.lfPitchAndFamily= FF_DONTCARE|DEFAULT_PITCH;// ファミリー
_tcscpy(logfont.lfFaceName,_T("MS ゴシック")); // フォント名
HFONT hFont = CreateFontIndirect(&logfont);
HFONT hDefFont = (HFONT)SelectObject(hdc,hFont);
// 直線描画
MoveToEx(hdc,10,100,NULL); // 始点をセット
LineTo(hdc,10,200); // 始点から割り当てられたペンで終点まで直線描画
// 曲線描画
POINT pt[4] = {};
pt[0].x = 50;pt[0].y = 50;
pt[1].x = 100;pt[1].y = 150;
pt[2].x = 50;pt[2].y = 250;
pt[3].x = 150;pt[3].y = 250;
// 点情報から割り当てられたペンでベジェ曲線描画、点の数は3の倍数+1でなければならない
PolyBezier(hdc,pt,4);
// 楕円描画
SelectObject(hdc,hNullPen); // 枠がいらない
RECT PointRect;
PointRect.left = -5;
PointRect.top = -5;
PointRect.right = 5;
PointRect.bottom = 5;
for(int i = 0;i < 4;++i)
Ellipse(hdc,pt[i].x + PointRect.left,pt[i].y + PointRect.top,pt[i].x + PointRect.right,pt[i].y + PointRect.bottom);
// 矩形描画
SelectObject(hdc,hNullPen); // 枠がいらない
RECT rect = {30,130,50,150};
Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); // ブラシで指定された矩形を塗りつぶす
// 画像表示
BitBlt(hdc,200,0,Bmp.bmWidth,Bmp.bmHeight,hBmpDC,0,0,SRCCOPY);
int X = 0;
int Y = 0;
// 文字列描画
const TCHAR* szText = _T("Hello World");
SetTextColor(hdc,RGB(0,0,255)); // 文字色を青に変更
TextOut(hdc,X,Y,szText,(int)_tcslen(szText)); // 文字列描画
// 使い終わったら元の描画オブジェクトに戻す
SelectObject(hdc,hDefPen);
SelectObject(hdc,hDefBrush);
SelectObject(hBmpDC, hDefBmp);
SelectObject(hdc, hDefFont);
// 使わなくなった描画オブジェクトは破棄
DeleteObject(hPen);
DeleteObject(hNullPen);
DeleteObject(hBrush);
DeleteObject(hBmp);
DeleteObject(hDefFont);
// 使わなくなったデバイスコンテキストを破棄
DeleteDC(hBmpDC);
// 描画終了
EndPaint(hWnd,&ps);
}
//------------------------------------------------------//
// ウィンドウ破棄メッセージ処理
//
// 引数: hWnd ウィンドウハンドル
//------------------------------------------------------//
void OnDestroy(HWND hWnd){
PostQuitMessage(0);
}
//-----------------------------------------------------//
// ウィンドウプロシージャ
// デフォルトの処理はDefWindowProc関数で行う
//
// 引数: hWnd ウィンドウハンドル
// msg メッセージ
// wParam パラメータ
// lParam パラメータ
//
// 戻り値:処理結果
//-----------------------------------------------------//
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam){
switch(msg){
HANDLE_MSG(hWnd,WM_PAINT,OnPaint);
HANDLE_MSG(hWnd,WM_DESTROY,OnDestroy);
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
描画を行うタイミングというものがあります(好きな時に描画していいわけではありません) HANDLE_MSG(hWnd,WM_PAINT,OnPaint); 描画するときは // 描画開始
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hWnd,&ps);
// ここに描画処理
// 描画終了
EndPaint(hWnd,&ps);
ペンを作成するには、 // ペン作成 HPEN hPen = CreatePen(PS_SOLID,5,RGB(255,0,0)); HPEN hNullPen = CreatePen(PS_NULL,1,RGB(0,0,0)); CreatePen関数の もっと詳しく知りたい人はmsdn公式を見てください ペンを作っただけでは描画に反映されません HPEN hDefPen = (HPEN)SelectObject(hdc,hPen); 他の描画オブジェクトに関しても割り当てないと反映されません HBRUSH hDefBrush = (HBRUSH)SelectObject(hdc,hBrush); SelectObject関数の戻り値はHGDIOBJ型となっていますが、 // 使い終わったら元の描画オブジェクトに戻す SelectObject(hdc,hDefPen); SelectObject(hdc,hDefBrush); SelectObject(hBmpDC, hDefBmp); SelectObject(hdc, hDefFont); 直線を描画するには、MoveTo関数で始点をセットし // 直線描画 MoveToEx(hdc,始点x座標,始点y座標,NULL); // 始点をセット LineTo(hdc,終点y座標,終点y座標); // 始点から割り当てられたペンで終点まで直線描画 続いて、曲線(ベジェ曲線)を描いてみます 緑の枠に囲まれた部分を凸包と呼び、 // 曲線描画
POINT pt[4] = {};
pt[0].x = 50;pt[0].y = 50;
pt[1].x = 100;pt[1].y = 150;
pt[2].x = 50;pt[2].y = 250;
pt[3].x = 150;pt[3].y = 250;
// 点情報から割り当てられたペンでベジェ曲線描画、点の数は3の倍数+1でなければならない
PolyBezier(hdc,点の配列,点の個数(3の倍数+1));
続いてブラシを作ってみます // ブラシ作成 HBRUSH hBrush = CreateSolidBrush(RGB(0,255,0)); ここでは、説明しませんが ブラシをデバイスコンテキストに割り当てた後 HBRUSH hDefBrush = (HBRUSH)SelectObject(hdc,hBrush); 図形を描画します // 楕円描画 SelectObject(hdc,hNullPen);// 枠がいらない RECT PointRect; PointRect.left = -5; PointRect.top = -5; PointRect.right = 5; PointRect.bottom = 5; for(int i = 0;i < 4;++i) Ellipse(hdc,pt[i].x + PointRect.left,pt[i].y + PointRect.top,pt[i].x + PointRect.right,pt[i].y + PointRect.bottom); 矩形を描画するには // 矩形描画
SelectObject(hdc,hNullPen); // 枠がいらない
RECT rect = {30,130,50,150};
Rectangle(hdc,rect.left,rect.top,rect.right,rect.bottom); // ブラシで指定された矩形を塗りつぶす
ビットマップ画像(.bmp)読み込みです
// ビットマップ読み込み
HINSTANCE hInstance = (HINSTANCE)GetModuleHandle(NULL); // インスタンスハンドル取得
HBITMAP hBmp = (HBITMAP)LoadImage(hInstance,_T("test.bmp"),IMAGE_BITMAP,0,0,LR_DEFAULTCOLOR | LR_SHARED | LR_LOADFROMFILE);
第一引数にはインスタンスハンドルを指定します ビットマップハンドルが取得できたら BITMAP Bmp; GetObject(hBmp,sizeof(BITMAP),&Bmp); GetObject関数で描画オブジェクトの情報を取得できます // ペン LOGPEN pen; GetObject(hPen,sizeof(LOGPEN),&pen); // ブラシ LOGBRUSH brush; GetObject(hPen,sizeof(LOGBRUSH),&brush); // フォント LOGFONT font; GetObject(hFont,sizeof(LOGFONT),&font); GetObjectしたBITMAP構造体のbmWidth,bmHeightに画像サイズが入っています HDC hBmpDC = CreateCompatibleDC(hdc); // 裏画面を作成します HBITMAP hDefBmp = (HBITMAP)SelectObject(hBmpDC, hBmp); ここで気を付けて欲しいのはSelectObject関数で画像を裏画面と対応づけることです // 画像表示 BitBlt(転送先デバイスコンテキスト,転送先X座標,転送先Y座標,画像幅,画像高さ,転送元デバイスコンテキスト,転送元X座標,転送元Y座標,ラスタオペレーションコード); BitBlt(hdc,200,0,Bmp.bmWidth,Bmp.bmHeight,hBmpDC,0,0,SRCCOPY); 第一引数は描画画面のデバイスコンテキストを指定します
ラスタオペレーションコードはどのように転送するかのフラグですSRCCOPYを指定するとそのまま画像が描画画面にコピーされます 続いて文字列描画です // フォント作成
LOGFONT logfont = {};
logfont.lfHeight = 30; // 文字高さ
logfont.lfWidth = 12; // 文字幅
logfont.lfEscapement = 30; // 文字送りの方向とX軸の角度
logfont.lfOrientation = logfont.lfEscapement; // ベースラインとX軸との角度
logfont.lfWeight = FW_BOLD; // フォントの太さ
logfont.lfItalic = TRUE; // イタリック体指定
logfont.lfUnderline = TRUE; // 下線付き指定
logfont.lfStrikeOut = TRUE; // 打ち消し線指定
logfont.lfCharSet = SHIFTJIS_CHARSET; // キャラクタセット
logfont.lfOutPrecision = OUT_DEFAULT_PRECIS; // 出力精度
logfont.lfClipPrecision = CLIP_DEFAULT_PRECIS; // クリッピングの精度
logfont.lfQuality = DEFAULT_QUALITY; // 出力品質
logfont.lfPitchAndFamily= FF_DONTCARE|DEFAULT_PITCH; // ファミリー
_tcscpy(logfont.lfFaceName,_T("MS ゴシック")); // フォント名
HFONT hFont = CreateFontIndirect(&logfont);
HFONT hDefFont = (HFONT)SelectObject(hdc,hFont);
LOGFONT構造体変数で SetTextColor関数で文字の色を変更し // 文字列描画
const TCHAR* szText = _T("Hello World");
SetTextColor(hdc,RGB(0,0,255)); // 文字色を青に変更
TextOut(hdc,X,Y,szText,(int)_tcslen(szText)); // 文字列描画
最後に、 // 使わなくなった描画オブジェクトは破棄 DeleteObject(hPen); DeleteObject(hNullPen); DeleteObject(hBrush); DeleteObject(hBmp); DeleteObject(hDefFont); // 使わなくなったデバイスコンテキストを破棄 DeleteDC(hBmpDC); 描画オブジェクトに関してはDeleteObject関数 さらに詳しい対応関係はMSDN公式を参照してください ふぅ・・・これで基本的な描画の説明は終わりました(^^;:) ここで全てを取り上げるの量的に不可能なので MSDN公式 しかし、冗長なコードですね 全ソースコードは下から
|