さて画面に文字が書けるようになったら、次はフォントや色を変更してみたくなりますね。
本日は、フォントの変更に挑戦しましょう。
CreateFontがない!
フォント生成サンプルを作成し、さてコンパイルしようとしましたが、CreateFontがなぜかコンパイル通りません。そうです、Windows Mobile には、フォント生成するための関数CreateFontが無いのです。
困った、これではフォントの変更はどうするのだと思いきや、CreateFontIndirect関数が使えるようです。
CreateFontとCreateFontIndirectは両方とも論理フォントを作成する関数です。違いは引数だけです。CreateFontは引数にフォント情報を渡しますが、CreateFontIndirectは引数にフォント情報を格納した構造体を渡します。
カスタムフォントの取得
自由にフォントを使いたい場合は、論理フォントを作成します。論理フォントの作成にはCreateFontIndirect関数を使います。
HFONT CreateFontIndirect(
CONST LOGFONT *lplf // フォントの特性
);
LOGFONT 構造体
typedef struct tagLOGFONT { LONG lfHeight; // フォントの高さ LONG lfWidth; // 平均文字幅 LONG lfEscapement; // 文字送り方向の角度 LONG lfOrientation; // ベースラインの角度 LONG lfWeight; // フォントの太さ BYTE lfItalic; // 斜体 BYTE lfUnderline; // 下線 BYTE lfStrikeOut; // 取り消し線 BYTE lfCharSet; // 文字セットの識別子 BYTE lfOutPrecision; // 出力精度 BYTE lfClipPrecision; // クリッピング精度 BYTE lfQuality; // 出力品質 BYTE lfPitchAndFamily; // ピッチとファミリ TCHAR lfFaceName[LF_FACESIZE]; // フォント名 } LOGFONT;
lfHeight にはフォントの高さをしてします。0を指定するとデフォルト値になります。
lfWidth には文字幅を指定します。これも0を指定すればデフォルト値になりますので通常は0でよいでしょう。
lfEscapement は文字送り方向の角度を1/10度単位で指定します。
lfOrientation はベースラインの角度です。通常、lfEscapement と同じ値を指定します。
lfWeight はフォントの太さです。0を指定するとデフォルト値(普通の太さ)になります。
lfItalic 、lfUnderline 、lfStrikeOut はそれぞれ、斜体、下線、取り消し線で、TRUEを指定すると適用されます。
lfCharSet は文字セット指定します。通常はSHIFTJIS_CHARSETで良いでしょう。他にANSI_CHASESTが指定できます。
lfOutPrecision は出力の精度を指定します。通常OUT_DEFAULT_PRECISで良いでしょう。
lfClipPrecision はクリッピング精度を指定します。通常CLIP_DEFAULT_PRECISで良いでしょう。
lfQuality は出力品質です。ANTIALIASED_QUALITYを指定するとアンチエイリアス処理がかかります。そのほかに、
DEFAULT_QUALITY:デフォルト
CLEARTYPE_QUALITY:クリアタイプ表示
NONANTIALIASED_QUALITY:アンチエイリアスなし
などを指定することができます。
lfPitchAndFamily は、フォントのピッチとファミリを指定します。フォント名で指定したフォントが存在しなかったときに使われるフォントになります。
ピッチにはDEFAULT_PITCH(規定値)、FIXED_PITCH(固定幅)、VARIABLE_PITCH (可変幅)のいずれかを指定します。
ファミリには
FF_DECORATIVE:装飾つきフォント
FF_DONTCARE:デフォルトフォント
FF_ROMAN:プロポーショナルフォント
FF_SCRIPT:手書き風フォント
FF_SWISS:プロポーショナルフォント
の中からいづれかを指定します。
lfFaceName にはフォント名を指定します。
フォントが不要になったら、DeleteObject関数で削除します。
SelectObject関数
フォントを使用するにはSelectObjectでフォントを選択して有効にする必要があります。
SelectObject関数
GDIオブジェクトを選択します。
HGDIOBJ SelectObject(
HDC hdc, // デバイスコンテキストのハンドル
HGDIOBJ hgdiobj // オブジェクトのハンドル
);
この関数は同じタイプの以前のオブジェクトを置き換えます。
戻り値に置き換えが発生する前のオブジェクトのハンドルが返ります。このハンドルを使用し、フォントを使用し終わった時にフォントを必ず元の(既定)オブジェクトに置き換えるようにしましょう。
以下のソースは、置き換えが発生する前のオブジェクトのハンドルをhFontOldに格納し、フォントの描画が終わったら、フォントを元に戻しています。
hFontOld = SelectObject(hdc,hFont); // フォントを設定する
// ここで文字の描画を行う
SelectObject(hdc,hFontOld); // フォントを元に戻す
ではソースを見てみましょう。
// text003.cpp
//
// Windowに文字を表示する
#include <windows.h>
#include <tchar.h>
#include <strsafe.h>
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
ATOM InitApp(HINSTANCE);
HWND InitInstance(HINSTANCE, int);
WCHAR szClassName[] = T("win02"); // ウィンドウクラス。UNICODEとしての文字列定数
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPTSTR lpCmdLine,int nShowCmd)
{
MSG msg;
BOOL bRet;
HWND hWnd;
if (!InitApp(hInstance))
return FALSE;
if (!(hWnd = InitInstance(hInstance,nShowCmd)))
return FALSE;
while((bRet = GetMessage(&msg, NULL, 0, 0)) != 0) {
if (bRet == -1){
break;
} else {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
return (int)msg.wParam;
}
// ウィンドウクラスの登録
ATOM InitApp(HINSTANCE hInst)
{
WNDCLASS wc;
wc.style = CS_HREDRAW|CS_VREDRAW;
wc.lpfnWndProc = WndProc; // プロシージャ名
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = hInst;
wc.hIcon = NULL; // 未サポート
wc.hCursor = NULL; // 未サポート
wc.hbrBackground= (HBRUSH) COLOR_WINDOW;
wc.lpszMenuName = NULL; // 未サポート
wc.lpszClassName=(LPCTSTR) szClassName;
return (RegisterClass(&wc));
}
// ウィンドウの生成
HWND InitInstance(HINSTANCE hInst, int nShowCmd)
{
HWND hWnd;
hWnd = CreateWindow(szClassName,T("Window Title"),
WS_CLIPCHILDREN, // ウィンドウの種類
CW_USEDEFAULT, // x座標
CW_USEDEFAULT, // y座標
CW_USEDEFAULT, // 幅
CW_USEDEFAULT, // 高さ
NULL, // 親ウィンドウのハンドル。親を作るのでNULL
NULL, // メニューハンドルまたは子ウィンドウID
hInst, // インスタンスハンドル
NULL);
if (!hWnd)
return FALSE;
ShowWindow(hWnd, nShowCmd);
UpdateWindow(hWnd);
return hWnd;
}
// ウィンドウプロシージャ
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wp, LPARAM lp)
{
PAINTSTRUCT ps;
HDC hdc;
LPTSTR lpszStr= T("WindowsMobile Win32APIプログラミング");
size_t size; // 文字列のサイズを格納する
StringCchLength(lpszStr,STRSAFE_MAX_CCH,&size); // 安全な文字列取得
static HFONT hFont;
HGDIOBJ hFontOld;
switch (msg){
// ウィンドウプロシージャは、ウィンドウが作成された直後で
// ウィンドウが表示される前にWM_CREATEメッセージを受け取ります。
case WM_CREATE:
LOGFONT logicalFont; // フォントの属性を定義
logicalFont.lfHeight = 20; // フォントの高さ
logicalFont.lfWidth = 0; // 平均文字幅
logicalFont.lfEscapement = 0; // 文字送り方向の角度
logicalFont.lfOrientation = 0; // ベースラインの角度
logicalFont.lfWeight = FW_BOLD; // フォントの太さ
logicalFont.lfItalic = TRUE; // 斜体
logicalFont.lfUnderline = TRUE; // 下線
logicalFont.lfStrikeOut = TRUE; // 取り消し線
logicalFont.lfCharSet = SHIFTJIS_CHARSET; // 文字セットの識別子
logicalFont.lfOutPrecision = OUT_DEFAULT_PRECIS; // 出力精度
logicalFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;// クリッピング精度
logicalFont.lfQuality = ANTIALIASED_QUALITY;// 出力品質
logicalFont.lfPitchAndFamily= FIXED_PITCH | FF_MODERN; // ピッチとファミリ
// フォント名
StringCchCopy(logicalFont.lfFaceName,32,T("MS ゴシック"));
hFont = CreateFontIndirect(&logicalFont);
case WM_PAINT:
hdc = BeginPaint(hWnd,&ps); // 描画処理を開始します。
hFontOld = SelectObject(hdc,hFont);
ExtTextOut(
hdc, // デバイスコンテキストのハンドル
0, // 開始位置(基準点)の x 座標
20, // 開始位置(基準点)の y 座標
NULL, // 長方形領域の使い方のオプション
NULL, // 長方形領域の入った構造体へのポインタ
lpszStr,// 文字列
size, // 文字数
NULL // 文字間隔の入った配列
);
SelectObject(hdc,hFontOld);
EndPaint(hWnd,&ps);
break;
case WM_DESTROY:
DeleteObject(hFont); // フォントの破棄を忘れずに行うこと!
PostQuitMessage(0);
break;
default:
return (DefWindowProc(hWnd, msg, wp, lp));
}
return 0;
}
WM_CREATEメッセージ
ウィンドウプロシージャは、ウィンドウが作成された直後のウィンドウが表示される前にWM_CREATEメッセージを受け取ります。
このプログラムでは、ウインドウプロシージャがWM_CREATEメッセージを受け取った時点で、CreateFontIndirect関数でカスタムフォント(論理フォント)を作成しています。
WM_DESTROYメッセージ(プログラムの終了時)を受け取った時に、DeleteObject関数を呼び出して作成した論理フォントを削除しています。
今日はここまで。