文字サイズの情報

フォントを変更すると、文字のサイズも変更されます。
環境によって使用されるフォントは異なるため、開発環境でのサイズ情報を数値で決め打ちすると別の環境でズレが生じる可能性があります。
ここでは文字サイズ取得の方法を説明します。

DrawText関数

DrawText関数の第五引数の書式設定にDT_CALCRECTフラグを指定することで、描画に必要な領域を計算して取得することができます。


#include <windows.h>
#include <strsafe.h>

//ウィンドウの生成等は省略

#define BUFFERSIZE 128

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

	static WCHAR* txt = L"あいうえお\n1234567890";
	static WCHAR* format =
		L"LEFT:\t\t%d\n"
		L"TOP:\t\t%d\n"
		L"RIGHT:\t\t%d\n"
		L"BOTTOM:\t%d\n";
	WCHAR buf[BUFFERSIZE];

	switch (message)
	{
	case WM_PAINT:
		GetClientRect(hWnd, &rtClient);
		hdc = BeginPaint(hWnd, &ps);

		//クライアント領域サイズをコピー
		rt = rtClient;
		//テキスト領域サイズを計算して取得
		DrawText(hdc, txt, -1, &rt, DT_WORDBREAK | DT_CALCRECT);
		//テキスト出力
		DrawText(hdc, txt, -1, &rt, DT_WORDBREAK);

		//サイズ情報の出力
		rtClient.top += rt.bottom + 20;
		StringCchPrintf(buf, BUFFERSIZE, format,
			rt.left, rt.top, rt.right, rt.bottom);
		DrawText(hdc, buf, -1, &rtClient, DT_WORDBREAK | DT_EXPANDTABS);

		EndPaint(hWnd, &ps);
		break;
		
	case WM_DESTROY: //ウィンドウの破棄
		PostQuitMessage(0);
		break;

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

実行結果です。

この処理はRECT構造体のrightメンバとbottomメンバのみが書き換えられます。
leftメンバとtopメンバにはあらかじめ0をセットしておく必要があります。

DT_WORDBREAKフラグを指定して複数行のサイズを取得する場合、あらかじめ描画領域の幅をRECT構造体に設定しておく必要があります
複数行文字列は、指定された幅に合わせて適宜改行をするためで、実際に何行になるかはこの幅を元に計算されるためです。
(rightメンバが0のままだとサイズ取得に失敗します)
文字列の幅が領域の幅に満たない場合は、幅の情報は適切なサイズに縮小されます。
行間の高さを含める場合はDT_EXTERNALLEADINGフラグを同時に指定します。

なお、このフラグを指定した場合は実際に文字列の描画は行われません。

GetTextMetrics関数

GetTextMetrics関数はフォントの情報を取得します。

BOOL GetTextMetrics(
 HDC hdc,
 LPTEXTMETRIC lptm
);
デバイスコンテキストhdcに設定されているフォントの情報を取得しlptmに格納する。
成功した場合は0以外を、失敗した場合は0を返す。

TEXTMETRICは構造体で、フォントの情報を格納します。
(頭の「LP」はポインタの意味です)

typedef struct tagTEXTMETRICW {
 LONG tmHeight;
 LONG tmAscent;
 LONG tmDescent;
 LONG tmInternalLeading;
 LONG tmExternalLeading;
 LONG tmAveCharWidth;
 LONG tmMaxCharWidth;
 LONG tmWeight;
 LONG tmOverhang;
 LONG tmDigitizedAspectX;
 LONG tmDigitizedAspectY;
 WCHAR tmFirstChar;
 WCHAR tmLastChar;
 WCHAR tmDefaultChar;
 WCHAR tmBreakChar;
 BYTE tmItalic;
 BYTE tmUnderlined;
 BYTE tmStruckOut;
 BYTE tmPitchAndFamily;
 BYTE tmCharSet;
} TEXTMETRICW, *PTEXTMETRICW, *NPTEXTMETRICW, *LPTEXTMETRICW;
フォントの基本情報を格納する構造体。

メンバが多いので簡単に説明します。

メンバ 説明
tmHeight フォントの高さ
(アセント+ディセント)
tmAscent アセント
(基準線より上の高さ)
tmDescent ディセント
(基準線より下の高さ)
tmInternalLeading 内部レディング
文字の上のアクセント記号等が表示される領域の高さ
(tmHeightに含まれる)
tmExternalLeading 外部レディング
文字の外側の領域(行間)の高さ
文字の描画による影響を受けない
(tmHeightに含まれない)
tmAveCharWidth フォントの平均幅
(斜体や太字は考慮されない)
tmMaxCharWidth フォントの最大幅
tmWeight フォントの太さ
tmOverhang 合成フォント(太字や斜体など)で使用される追加の幅
通常のフォントより広い領域が必要になるフォントで、元のフォントから広げられる量
tmDigitizedAspectX そのデバイスでの水平アスペクト
tmDigitizedAspectY そのデバイスでの垂直アスペクト
tmFirstChar フォントで定義されている最初の文字
tmLastChar フォントで定義されている最後の文字
tmDefaultChar デフォルトの文字
フォントに存在しない文字を使用したときの置き換えに使用される
tmBreakChar 単語と単語の間を表す文字
tmItalic 0以外の値ならフォントはイタリック体
tmUnderlined 0以外の値ならフォントは下線を持つ
tmStruckOut 0以外の値ならフォントは打消し線を持つ
tmPitchAndFamily フォントのピッチとファミリ
tmCharSet フォントの文字セット
(→CreateFont関数#iCharSet)

フォントのいくつかの設定はプログラマが設定した上で使用しますが、実際に描画される大きさは各フォントによって異なるのでこの関数で取得する必要があります。

フォントの縦幅は以下の図のように複数のパートから成り立っています。
フォントサイズの詳細