文字列の幅


ジャスティフィケーションスペース

高度な文字列の描画処理を行う場合、単純に TextOut() を使うだけでは実現できません
とくに、対象となる文字列全体の幅の情報は重要です

Win32 API は、文字列全体の幅と高さを取得する
GetTextExtentPoint32() を提供しています
BOOL GetTextExtentPoint32(
	HDC hdc , LPCTSTR lpString ,
	int cbString , LPSIZE lpSize
);
hdc にはデバイスコンテキストのハンドルを
lpString は、幅を調べる文字列へのポインタを指定します
cbString には、lpString の文字列の文字数を指定します
lpSize は、結果を格納する SIZE 構造体へのポインタです
関数が成功すれば 0 以外、失敗すれば 0 が返ります

SIZE 構造体は次のように定義されています
typedef struct tagSIZE { // siz 
    LONG cx; 
    LONG cy; 
} SIZE;
cs は矩形の幅が、cy は矩形の高さを表しています
構造体が表す論理的意味と名前が違うというだけで、POINT 構造体と同じです

この値を使えば、単語を区切るスペースの幅をクリップに合わせて拡張できます
文字列中の区切り文字に、指定幅を追加するには
SetTextJustification() 関数を用います

BOOL SetTextJustification(HDC hdc , int nBreakExtra , int nBreakCount);

hdc にはデバイスコンテキストのハンドルを指定します
nBreakExtra は、行に追加するスペースの合計幅を論理単位で指定します
例えば、クリッピング領域の幅が 100 で、文字列の幅が 45 ならば 55 がスペース幅となります
nBreakCount は、その行に含まれる区切り文字の数を指定します
関数が成功すれば 0 以外、失敗すれば 0 が返ります
#include <windows.h>

#define TITLE TEXT("Kitty on your lap")

LRESULT CALLBACK WndProc(HWND hWnd , UINT msg , WPARAM wp , LPARAM lp) {
	HDC hdc;
	PAINTSTRUCT ps;
	RECT rect;
	SIZE size;

	switch (msg) {
	case WM_DESTROY:
		PostQuitMessage(0);
		return 0;
	case WM_PAINT:
		hdc = BeginPaint(hWnd , &ps);

		GetClientRect(hWnd , &rect);
		GetTextExtentPoint32(hdc , TITLE , lstrlen(TITLE) , &size);
		SetTextJustification(hdc , rect.right - size.cx , 3);
		TextOut(hdc , 0 , 10 , 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;
}


このプログラムは、文字列がクライアント領域にピッタリと納まるように
文字列幅を取得し、これに合わせて単語の間に十分なスペースを追加しています


GetTextExtentPoint32()

BOOL GetTextExtentPoint32(
	HDC hdc , LPCTSTR lpString ,
	int cbString , LPSIZE lpSize
);
文字列の幅と高さを取得します

hdc - デバイスコンテキストのハンドルを指定します
lpString - 幅と高さを調べる文字列へのポインタを指定します
cbString - 文字列の文字数を指定します
lpSize - 結果を格納する SIZE 構造体へのポインタを指定します

戻り値 - 成功すれば 0 以外。失敗すれば 0

SetTextJustification()

BOOL SetTextJustification(HDC hdc , int nBreakExtra , int nBreakCount);

文字列中の区切り文字に追加するスペースの大きさを指定します

hdc - デバイスコンテキストを指定します
nBreakExtra - 行に追加する合計スペースを論理単位で指定します
nBreakCount - 行に含まれる区切り文字数を指定します

戻り値 - 成功すれば 0 以外。失敗すれば 0



前のページへ戻る次のページへ