コントロールのフォントを設定してみる

前回まで作成してきたタブコントロールでは、タブのラベル部分に表示されている文字にはデフォルトフォントが使われていました。今回は、ラベルに表示されるフォントを設定してみましょう。

コントロールのフォント



タブコントロールに限らず、文字が表示されるWindows標準コントロールやコモンコントロールは、 WM_SETFONT メッセージを送ることによってフォントを設定することができます。しかし、そのためには、フォントオブジェクトがあらかじめ作成あるいは取得されていなくてはなりません。フォントを作成あるいは取得するにはいくつかの方法があります。

これらのうちで最も簡単な方法は、システム定義フォントを使うなら2番目の方法、任意のフォントを使うなら3番目の方法でしょう。

逆に1番目の方法は処理が非常に煩雑で、細かい設定をしたい場合以外にはあまりお勧めはできません。ここでも説明はしません。

システム定義のフォントを使用する

まずはシステム定義のフォントオブジェクトを取得して、それをコントロールに割り当てる方法を説明します。

システム定義のフォントを取得するには GetStockObject 関数を呼び出します。

HGDIOBJ GetStockObject(
    int fnObject   // ストックオブジェクトの型
);

この関数の引数(fnObject パラメータ)には、取得するストックオブジェクトの種類を指定します。指定する値と取得されるフォントの種類の対応は以下のようになります。これらの値は、 sysfont 命令で指定する値と同じです。

意味
10 (OEM_FIXED_FONT) OEM 文字セットの固定幅フォント
11 (ANSI_FIXED_FONT) Windows 文字セットの固定幅システムフォント
12 (ANSI_VAR_FONT) Windows 文字セットの可変幅システムフォント
13 (SYSTEM_FONT) システムフォント。デフォルトでメニューやダイアログボックスなどで使われる可変幅フォント。
17 (DEFAULT_GUI_FONT) ユーザーインターフェイス用のデフォルトフォント (メニューやダイアログボックスなどで使われる)

GetStockObject 関数は、戻り値として取得されたフォントのハンドルを返します。


フォントの取得ができたら、コントロールに WM_SETFONT メッセージを送信します。

#define WM_SETFONT        0x0030

WM_SETFONT
    wParam = hFont;
    lParam = fRedraw;

hFont パラメータには、取得したフォントのハンドルを指定します。

fRedraw パラメータには、コントロールを直ちに再描画するかどうかを示す値を指定します。直ちに再描画するには 1 (TRUE) を、そうでない場合には 0 (FALSE) を指定します。

以上の操作で、コントロールのフォントが設定されます。

; システム定義フォントを取得
pm = 17                 ; DEFAULT_GUI_FONT(デフォルトGUIフォント)
dllproc "GetStockObject", pm, 1, D_GDI
hFont = stat            ; フォントハンドル

; WM_SETFONT メッセージ送信
pm.0 = hControl         ; コントロールのハンドル
pm.1 = 0x0030           ; WM_SETFONT
pm.2 = hFont            ; フォントハンドル
pm.3 = 1                ; 再描画フラグ
sendmsg pm

HSPウィンドウのフォントを使用する

次に、HSPウィンドウに割り当てられているフォントのハンドルをそのままコントロールに割り当てる方法を説明します。

HSPウィンドウに割り当てられているフォントのハンドルは BMSCR 構造体に格納されているので、 mref 命令を使えば取得できるようになります。後は、このハンドルをパラメータとして WM_SETFONT メッセージを送れば設定できます。

; HSPウィンドウのフォントを設定
font "MS ゴシック", 14, 1

; 描画中ウィンドウのフォントオブジェクト取得
mref bmscr, 67          ; 描画中ウィンドウの BMSCR 構造体
hFont = bmscr.38        ; フォントハンドル

; WM_SETFONT メッセージ送信
pm.0 = hControl         ; コントロールのハンドル
pm.1 = 0x0030           ; WM_SETFONT
pm.2 = hFont            ; フォントハンドル
pm.3 = 1                ; 再描画フラグ
sendmsg pm

実はこの方法には1つだけ問題点があります。それは、この方法でフォントを設定した後に、再び font 命令などでHSPウィンドウに割り当てられているフォントを変更してしまうと、以前のフォントが解放されて、コントロールに割り当てたフォントハンドルが無効になってしまうために、コントロールに表示されている文字がデフォルトフォントに戻ってしまうということです。

この問題を防ぐには、いくつかの方法があります。

まず1つ目の方法として、当然のことですが、ウィンドウのフォントの設定を変更しないことです。フォントを変更しなければそのフォントは解放されませんので。

次に2つ目の方法としては、コントロールのフォントを設定した後で font 命令を使用した場合には、必要な描画を行った後ですぐにまた上記の方法でコントロールのフォントの設定を行なうというものです。

3つ目の方法として、コントロールのフォント設定専用のウィンドウを準備するという方法があります。HSPでは、使用されるウィンドウ一つ一つにそれぞれ別のフォントが割り当てられています。そのため、 font 命令で描画中ウィンドウのフォントを変更しても、他のウィンドウのフォントは変更されないようになっているのです。そこで、この特性を利用して、専用のウィンドウを1つ作っておいて、これにコントロール専用のフォントを割り当ててしまいます。そして、このウィンドウの BMSCR 構造体から取得したフォントハンドルをコントロールに設定するのです。新しくバッファウィンドウを作成してもいいですし(この場合はメモリ節約のためサイズを小さくとりましょう)、他のウィンドウで文字を描画しないウィンドウがあれば、そのウィンドウに割り当ててもかまいません。

4つ目の方法は、HSPウィンドウのフォントを元に、新しいフォントオブジェクトを作成するというものです。コントロールのフォントのためにわざわざ新しいウィンドウを作成するのはちょっと……という方はこの方法を使ってみましょう。この方法は次で紹介します。

HSPウィンドウのフォントを元にフォントを作成する

HSPウィンドウのフォントを元にして、新しいフォントを作成する方法を紹介します。この方法では、やや大きめの、見慣れない構造体が出てくるので、ちょっととっつきにくいところがありますが、スクリプト上で行なう処理自体はたいしたことはありません。

順序としては、まず、HSPウィンドウに割り当てられているフォントのハンドルを GetObject 関数に渡してフォントの情報を LOGFONT 構造体に格納した後、その構造体をそのまま CreateFontIndirect 関数に渡してフォントを作成します。

まずは、 GetObject 関数を呼び出します。

int GetObjectA(
    HGDIOBJ hgdiobj,  // オブジェクトのハンドル
    int     cbBuffer, // バッファサイズ
    PVOID   pvObject  // 情報を格納するバッファ
);

今回はHSPウィンドウに割り当てられているフォントの情報を取得するので、第1引数(hgdiobj パラメータ)にはそのフォントハンドルを BMSCR 構造体から取得して指定します。

第2引数(cbBuffer パラメータ)には LOGFONT 構造体のサイズである 60 を、第3引数(lpvObject パラメータ)にはフォントの情報を格納するための LOGFONT 構造体のアドレスをそれぞれ指定します。

LOGFONT 構造体は以下のように定義されています。

typedef struct tagLOGFONT {
    LONG  lfHeight;            // 文字セルまたは文字の高さ
    LONG  lfWidth;             // 平均文字幅
    LONG  lfEscapement;        // 文字送りの方向とX軸との角度
    LONG  lfOrientation;       // ベースラインとX軸との角度
    LONG  lfWeight;            // フォントの太さ
    BYTE  lfItalic;            // イタリック体指定
    BYTE  lfUnderline;         // 下線付き指定
    BYTE  lfStrikeOut;         // 打ち消し線付き指定
    BYTE  lfCharSet;           // キャラクタセット
    BYTE  lfOutPrecision;      // 出力精度
    BYTE  lfClipPrecision;     // クリッピングの精度
    BYTE  lfQuality;           // 出力品質
    BYTE  lfPitchAndFamily;    // ピッチとファミリ
    TCHAR lfFaceName[32];      // フォント名
} LOGFONT *PLOGFONT, NEAR *NPLOGFONT, FAR *LPLOGFONT;

この構造体はフォントの情報を格納するためのものです。各メンバの説明はここでは省きます。

さて、フォントの情報を取得できたら、 CreateFontIndirect 関数を呼び出します。

HFONT CreateFontIndirectA(
    CONST LOGFONT *plogfont // フォント情報を格納した構造体
);

この関数は LOGFONT 構造体に格納されている情報を元にして、新しいフォントオブジェクトを作成します。この関数の引数(plogfont パラメータ)には、先ほど GetObject 関数でフォント情報を格納した LOGFONT 構造体のアドレスを指定します。この関数は、戻り値として作成されたフォントのハンドルを返します。

以上でフォントオブジェクトが作成されたので、あとは WM_SETFONT メッセージでコントロールに割り当てれば完了です。

; HSPウィンドウのフォントを設定
font "MS ゴシック", 14, 1

; 描画中ウィンドウのフォントオブジェクト取得
mref bmscr, 67          ; 描画中ウィンドウの BMSCR 構造体
hFontOrg = bmscr.38     ; HSPウィンドウのフォントハンドル

; フォントの情報を取得
pm = hFontOrg           ; HSPウィンドウのフォントハンドル
pm.1 = 60               ; LOGFONT 構造体のサイズ
getptr pm.2, logfont    ; LOGFONT 構造体のアドレス
dllproc "GetObjectA", pm, 3, D_GDI

; 新しいフォントオブジェクトを作成
getptr pm, logfont      ; LOGFONT 構造体のアドレス
dllproc "CreateFontIndirectA", pm, 1, D_GDI
hFont = stat            ; HSPウィンドウのフォントハンドル

; WM_SETFONT メッセージ送信
pm.0 = hControl         ; コントロールのハンドル
pm.1 = 0x0030           ; WM_SETFONT
pm.2 = hFont            ; フォントハンドル
pm.3 = 1                ; 再描画フラグ
sendmsg pm

この方法で新しいフォントを作成した場合、コントロールをもう使わないなどの理由でフォントが不要になったら、 DeleteObject 関数を使ってフォントを削除するようにしてください。


今回はサンプルスクリプトはありません。