ペン

今までの図形の描画では、線はすべて黒の細い線で描画されていました。
線の色や種類は変更することができます。

ストックオブジェクト

図形の線はペンというオブジェクトによって描画されます。
ペンはストックオブジェクトにあらかじめ用意されています。
(→GetStockObject関数)

定数 説明
WHITE_PEN 白色のペン
BLACK_PEN 黒色のペン
NULL_PEN 透明ペン
(何も描画しない)
DC_PEN 色を変更可能なペン

初期状態ではBLACK_PENがデバイスコンテキストに設定されています。

SetDCPenColor関数

DC_PENSetDCPenColor関数で色を設定できます。

COLORREF SetDCPenColor(
 HDC hdc,
 COLORREF color
);
DC_PENの色を設定する。
戻り値は設定した色。
失敗した場合はCLR_INVALIDを返す。

COLORREF型に関しては文字色と背景色の項を参照してください。


case WM_PAINT: //ウィンドウの描画
	hdc = BeginPaint(hWnd, &ps);

	SetDCPenColor(hdc, RGB(255, 0, 0));
	SelectObject(hdc, GetStockObject(DC_PEN));

	//何か描画
	MoveToEx(hdc, 10, 10, NULL);
	LineTo(hdc, 110, 110);
	
	EndPaint(hWnd, &ps);
	break;

GetDCPenColor関数

GetDCPenColor関数はDC_PENに設定されている色を取得します。

COLORREF GetDCPenColor(
 HDC hdc,
);
DC_PENの色を取得する。

CreatePen関数

ストックオブジェクトのペンは種類が少ないので、詳細な設定を行う場合は自分でペンを定義します。
ペンの作成はCreatePen関数で行います。

HPEN CreatePen(
 int iStyle,
 int cWidth,
 COLORREF color
);
論理ペンを作成する。

第一引数iStyleは、後述するペンのスタイルを示す定数を指定します。
第二引数cWidthはペンの幅(太さ)です。
第三引数colorはペンの色です。

ペンのスタイル定数は以下のものを指定します。

定数 説明
PS_SOLID 実線
PS_DASH 破線
ペン幅は1以下にする必要がある
PS_DOT 点線
ペン幅は1以下にする必要がある
PS_DASHDOT PS_DASH→PS_DOTの繰り返し
ペン幅は1以下にする必要がある
PS_DASHDOTDOT PS_DASH→PS_DOT→PS_DOTの繰り返し
ペン幅は1以下にする必要がある
PS_NULL 透明ペン(描画しない)
PS_INSIDEFRAME 実線
Rectangle関数などの「内側」を持つ図形で使用すると、内側からはみ出さないように描画される
(図形は縮小される)

CreatePen関数はHPEN型を返します。
これはGDIオブジェクトで、不要になったらDeleteObject関数で破棄する必要があります。


//ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HDC hdc;
	PAINTSTRUCT ps;

	HPEN pen;
	HGDIOBJ hgdi;

	switch (message)
	{
	case WM_PAINT: //ウィンドウの描画
		hdc = BeginPaint(hWnd, &ps);

		//実線、太さ3、赤
		pen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
		hgdi = SelectObject(hdc, pen);
		MoveToEx(hdc, 10, 10, NULL);
		LineTo(hdc, 110, 10);
		SelectObject(hdc, hgdi);
		DeleteObject(pen);

		//破線、太さ1、青
		pen = CreatePen(PS_DASH, 1, RGB(0, 255, 0));
		hgdi = SelectObject(hdc, pen);
		MoveToEx(hdc, 10, 20, NULL);
		LineTo(hdc, 110, 20);
		SelectObject(hdc, hgdi);
		DeleteObject(pen);

		//点線、太さ1、緑
		pen = CreatePen(PS_DOT, 1, RGB(0, 0, 255));
		hgdi = SelectObject(hdc, pen);
		MoveToEx(hdc, 10, 30, NULL);
		LineTo(hdc, 110, 30);
		SelectObject(hdc, hgdi);
		DeleteObject(pen);

		//PS_SOLID、太さ6、赤
		pen = CreatePen(PS_SOLID, 6, RGB(255, 0, 0));
		hgdi = SelectObject(hdc, pen);
		Rectangle(hdc, 120, 10, 220, 60);
		SelectObject(hdc, hgdi);
		DeleteObject(pen);

		//PS_INSIDEFRAME、太さ6、赤
		pen = CreatePen(PS_INSIDEFRAME, 6, RGB(255, 0, 0));
		hgdi = SelectObject(hdc, pen);
		Rectangle(hdc, 120, 70, 220, 120);
		SelectObject(hdc, hgdi);
		DeleteObject(pen);

		EndPaint(hWnd, &ps);
		break;

	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}

様々なペンで描画した結果です。
様々なペンの作成

四角形の上側はPS_SOLID、下側はPS_INSIDEFRAMEに設定しています。
サイズの指定は同じですが、PS_INSIDEFRAMEで描画した四角形は、PS_SOLIDで描画した四角形よりも少し小さくなっているのがわかると思います。
PS_SOLIDは枠線の左右にペンの太さを反映させるのに対し、PS_INSIDEFRAMEは領域からはみ出さないように、枠線の内側にペンの太さが反映させるためです。

なお、破線や点線は実際には線の色と背景色とが交互に描画されています。
(ウィンドウの背景色ではなく、デバイスコンテキストに設定されている背景色)
背景色の変更はSetBkColor関数で行えます。
SetBkMode関数でTRANSPARENT(透明モード)に設定すると、線と線の間は描画されません。
(→背景色の変更)

CreatePenIndirect関数

ペンの作成はCreatePenIndirect関数を使用することもできます。
引数の中身が違うだけで使い方は同じです。

HPEN CreatePenIndirect(
 const LOGPEN *plpen
);
論理ペンを作成する。

LOGPENは構造体です。

typedef struct tagLOGPEN {
 UINT lopnStyle;
 POINT lopnWidth;
 COLORREF lopnColor;
} LOGPEN, *PLOGPEN, *NPLOGPEN, *LPLOGPEN;
論理ペンの情報を格納する構造体。

CreatePen関数の引数をそのまま格納するのがLOGPEN構造体です。
ただし、線の太さを指定するlopnWidthメンバの型がint型ではなくPOINT型になっています。
LOGPEN構造体では、POINT構造体のxメンバのみを使用します。
yメンバは使用されません。


HPEN hPen;
LOGPEN logPen;

logPen.lopnStyle = PS_SOLID;
logPen.lopnWidth.x = 3;
logPen.lopnColor = RGB(255, 0, 0);
hPen = CreatePenIndirect(&logPen);