文字列の幅
ジャスティフィケーションスペース
高度な文字列の描画処理を行う場合、単純に 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