テキストの描画

TextOut 関数

次の図のように,クライアント領域にテキストを描画するプログラムを作ります。

作例

#include <windows.h>

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
    TCHAR szAppName[] = TEXT("TestApp");
    WNDCLASS wc;
    HWND hwnd;
    MSG msg;

    wc.style         = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc   = WndProc;
    wc.cbClsExtra    = 0;
    wc.cbWndExtra    = 0;
    wc.hInstance     = hInstance;
    wc.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
    wc.hCursor       = LoadCursor(NULL, IDC_ARROW);
    wc.hbrBackground = (HBRUSH) (COLOR_WINDOW + 1);
    wc.lpszMenuName  = NULL;
    wc.lpszClassName = szAppName;

    if (!RegisterClass(&wc)) return 0;

    hwnd = CreateWindow(
        szAppName, TEXT(""),
        WS_OVERLAPPEDWINDOW,
        CW_USEDEFAULT, CW_USEDEFAULT,
        CW_USEDEFAULT, CW_USEDEFAULT,
        NULL, NULL,
        hInstance, NULL);

    if (!hwnd) return 0;

    ShowWindow(hwnd, nCmdShow);
    UpdateWindow(hwnd);

    while (GetMessage(&msg, NULL, 0, 0) > 0) {
        TranslateMessage(&msg);
        DispatchMessage(&msg);
    }

    return msg.wParam;
}

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static TCHAR szText[] = TEXT("This is some sample text.");
    static int nTextLen = sizeof szText / sizeof(TCHAR) - 1;
    HDC hdc;
    PAINTSTRUCT ps;

    switch (uMsg) {
    case WM_CREATE:
        return 0;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        TextOut(hdc, 0, 0, szText, lstrlen(szText));
        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

TextOut 関数は,テキストを描画する関数の中で最も単純な関数です。

TextOut 関数 [MSDN]

テキストを描画します。

BOOL TextOut(
    HDC hdc,           // デバイスコンテキストへのハンドル
    int nXStart,       // 基準点の x 座標
    int nYStart,       // 基準点の y 座標
    LPCTSTR lpString,  // 文字列
    int cbString       // 文字数
);

Windows API における "文字数" とは,lstrlen 関数の返す文字数のことです。
lstrlen 関数は (文字列のバイト数) / sizeof(TCHAR) に等しい値を返します (*1)。

sizeof(TEXT("aiuあいう"))lstrlen(TEXT("aiuあいう"))
UNICODE 未定義109
UNICODE 定義済146

(*1) lstrlen 関数は,記号 UNICODE が未定義の時 strlen に,定義済の時 wcslen にそれぞれ等価です。詳しくは Unicode 対応 にて説明しています。

文字色と背景色

次のプログラムは,テキストを赤色で描画します。また,テキストの背景を薄い赤色で塗り潰します。

作例

#include <windows.h>

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
    // 省略
}

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static TCHAR szText[] = TEXT("This is some sample text.");
    HDC hdc;
    PAINTSTRUCT ps;

    switch (uMsg) {
    case WM_CREATE:
        return 0;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        SetTextColor(hdc, RGB(0xff, 0x00, 0x00));  // 文字色を設定
        SetBkColor(hdc, RGB(0xff, 0xdf, 0xdf));    // 背景色を設定
        TextOut(hdc, 0, 0, szText, lstrlen(szText));
        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

デバイスコンテキストの文字色を変更するには SetTextColor 関数を使います。
この関数で設定された文字色は,TextOut 関数,ExtTextOut 関数で反映されます。

SetTextColor 関数 [MSDN]

デバイスコンテキストの文字色を設定します。

COLORREF SetTextColor(
    HDC hdc,          // デバイスコンテキストへのハンドル
    COLORREF crColor  // 色
);
返り値
以前の文字色を返します。失敗時には CLR_INVALID を返します。

文字列の背景色を変えるには,SetBkColor 関数でデバイスコンテキストの背景色を設定します。

SetBkColor 関数 [MSDN]

デバイスコンテキストの背景色を設定します。

COLORREF SetBkColor(
    HDC hdc,          // デバイスコンテキストへのハンドル
    COLORREF crColor  // 色
);
返り値
以前の背景色を返します。失敗時には CLR_INVALID を返します。

この関数で設定した背景色は,次のような場所で使用されます。

この作例では使用していませんが,デバイスコンテキストの背景モードを設定する SetBkMode もあります。
背景モードを変更すれば,テキスト等の背景を塗り潰さずに透過させることができます。

SetBkMode 関数 [MSDN]

デバイスコンテキストの背景モードを設定します。

int SetBkColor(
    HDC hdc,     // デバイスコンテキストへのハンドル
    int iBkMode  // 背景モード
);
iBkMode

背景モード [MSDN]

説明
OPAQUE背景を塗り潰す
TRANSPARENT背景を塗り潰さない

なお,SetTextColor, SetBkColor, SetBkMode の各関数と対になる,GetTextColor, GetBkColor, GetBkMode 関数も提供されています。

テキストの配置

次のプログラムは,文字列を右揃えで描画します。

作例

#include <windows.h>

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
    // 省略
}

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static TCHAR szText1[] = TEXT("This is some");
    static TCHAR szText2[] = TEXT("sample text.");
    static int cxClient;
    HDC hdc;
    PAINTSTRUCT ps;

    switch (uMsg) {
    case WM_CREATE:
        return 0;

    case WM_SIZE:
        cxClient = LOWORD(lParam);
        return 0;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        SetTextAlign(hdc, TA_RIGHT | TA_TOP);  // 右揃えに設定
        TextOut(hdc, cxClient, 0,  szText1, lstrlen(szText1));
        TextOut(hdc, cxClient, 20, szText2, lstrlen(szText2));
        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

テキストの配置を変更するには SetTextAlign 関数を使います。

SetTextAlign 関数 [MSDN]

デバイスコンテキストの配置設定を設定します。

COLORREF SetTextColor(
    HDC hdc,          // デバイスコンテキストへのハンドル
    COLORREF crColor  // 色
);
fMode
テキストの配置方法を指定します。次に示す値はビット論理和で組み合わせて指定できます。

テキスト配置 [MSDN]

値 (現在位置)説明
TA_NOUPDATECP現在位置を更新しない (既定)
TA_UPDATECP現在位置を更新する
値 (水平方向)説明
TA_LEFT左寄せ (既定)
TA_RIGHT右寄せ
TA_CENTER中央揃え
値 (垂直方向)説明
TA_TOP上に揃える (既定)
TA_BOTTOM下に揃える
TA_BASELINEベースラインを揃える
返り値
以前の配置を返します。失敗時には GDI_ERROR を返します。

テキストの配置設定を変更すると,TextOut 関数,ExtTextOut 関数の基準点が変わります。
次の図は,各テキスト配置を適用した時の基準点の位置を赤色で示したものです。

基準点の位置

なお,現在の配置を取得できる GetTextAlign 関数もあります。

## フォントの利用

このプログラムでは,固定幅フォントを使って文字列を描画します。

作例

#include <windows.h>

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);

int WINAPI WinMain(
    HINSTANCE hInstance, HINSTANCE hPrevInstance,
    LPSTR lpszCmdLine, int nCmdShow)
{
    // 省略
}

LRESULT CALLBACK WndProc(
    HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
    static TCHAR szText[] = TEXT("This is some sample text.");
    static HFONT hfon, hfonPrev;
    HDC hdc;
    PAINTSTRUCT ps;

    switch (uMsg) {
    case WM_CREATE:
        hfon = (HFONT) GetStockObject(OEM_FIXED_FONT); // フォントを取得
        return 0;

    case WM_PAINT:
        hdc = BeginPaint(hwnd, &ps);
        hfonPrev = (HFONT) SelectObject(hdc, hfon);  // フォントを選択
        TextOut(hdc, 0, 0, szText, lstrlen(szText));
        SelectObject(hdc, hfon);                     // 元に戻す
        EndPaint(hwnd, &ps);
        return 0;

    case WM_DESTROY:
        PostQuitMessage(0);
        return 0;
    }

    return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

今回のプログラムは,ペンとブラシ の章で紹介した,ストックオブジェクトを利用しています。
フォントへのハンドルの型は HFONT 型です。