
前回作成したリッチエディットでは、フォントを設定するのに自分で入力しなければなりませんでした。今回は、Windowsがあらかじめ持っているコモンダイアログボックスの1つ、フォント選択ダイアログボックスを使ってフォントを設定してみましょう。
フォント設定ダイアログの作成手順は以下のようになります。
まず、 CHOOSEFONT 構造体の各メンバに情報を格納します。
typedef struct {
DWORD lStructSize; // 構造体サイズ(=60)
HWND hwndOwner; // オーナーウィンドウハンドル
HDC hDC; // プリンタのデバイスハンドル
LPLOGFONT lpLogFont; // LOGFONT構造体のアドレス
INT iPointSize; // サイズ(ポイント数)
DWORD Flags; // フラグ
DWORD rgbColors; // 文字色
LPARAM lCustData; // 32ビット値
LPCFHOOKPROC lpfnHook; // フックプロシージャアドレス
LPTCSTR lpTemplateName; // テンプレートリソース名
HINSTANCE hInstance; // モジュールインスタンス
LPTSTR lpszStyle; // スタイルデータ
WORD nFontType; // フォントタイプ
WORD ___MISSING_ALIGNMENT__;
INT nSizeMin; // サイズ最小値
INT nSizeMax; // サイズ最大値
} CHOOSEFONT, *LPCHOOSEFONT;
とりあえず、必要なメンバのみ説明しましょう。
lStructSize メンバには構造体サイズの60を指定しておきます。
hwndOwner には、表示するダイアログのオーナーウィンドウのハンドルを指定します。ここにはHSPウィンドウのハンドルを指定しておけばOKです。
lpLogFont メンバには、フォントの情報を格納するための LOGFONT 構造体のアドレスを指定します。この構造体には、選択されたフォントの情報が格納されます。
Flags メンバにはオプションフラグを指定します。CF_SCREENFONTS (0x00000001) をまず指定しましょう。これはシステムがサポートするフォントを表示します。また、CF_INITTOLOGFONTSTRUCT (0x00000040) を指定しておくことで、lpLogFont メンバの指す LOGFONT 構造体の情報で、初期の状態で選択されているフォントを指定することができます。他にも、CF_EFFECTS (0x00000100) を指定することで、打ち消し線・下線・文字色などの指定をすることもできるようになります。
CHOOSEFONT 構造体に情報を格納できたら、 ChooseFont 関数を呼び出します。
BOOL ChooseFontA(
LPCHOOSEFONT pcf // 初期化情報を格納した構造体
);
引数として、情報を格納した CHOOSEFONT 構造体のアドレスを指定します。
フォントが正しく選択されると、 CHOOSEFONT 構造体の iPointSize, rgbColors, nFontType などのメンバおよび lpLogFont メンバが指し示す LOGFONT 構造体の各メンバに、選択されたフォントの情報が格納されます。
さて、これをリッチエディットで使用するために、フォントダイアログで選択されたフォントの情報を CHARFORMAT 構造体に格納することを考えてみましょう。
先ほども述べた通り、選択されたフォントの情報は CHOOSEFONT 構造体と LOGFONT 構造体に格納されます。各メンバを以下のように対応させればいいでしょう。
| 構造体 | メンバ | → | CHARFORMAT 構造体メンバ |
|---|---|---|---|
| CHOOSEFONT | iPointSize | → | yHeight(単位換算が必要) |
| rgbColors | → | crTextColor | |
| nFontTypeのBOLD_FONTTYPE値 | → | dwEffectsのCFE_BOLD値 | |
| nFontTypeのITALIC_FONTTYPE値 | → | dwEffectsのCFE_ITALIC値 | |
| LOGFONT | lfUnderline | → | dwEffects のCFE_UNDERLINE値 |
| lfStrikeOut | → | dwEffects のCFE_STRIKEOUT値 | |
| lfCharSet | → | bCharSet | |
| lfPichAndFamily | → | bPichAndFamily | |
| lfFaceName | → | szFaceName |
CHOOSEFONT 構造体の iPointSize メンバに格納されるフォントサイズは 1/10 ポイント単位の値なので、 CHARFORMAT 構造体の yHeight メンバに格納するには twip 単位に変換します。1 ポイント = 20 twips なので、
yHeight = iPointSize * 2
とします。
LOGFONT 構造体の lfHeight メンバにもフォントの高さが格納されますが、これは論理単位で指定されています。論理単位とはGDIが使用する概念的な長さの単位のことで、ピクセル数などの物理的な単位(デバイス単位)とは異なるものです。論理単位とデバイス単位の間の関係は、デバイスコンテキストに設定されたマッピングモードによって異なりますが、たいていの場合は(HSPウィンドウも)1論理単位は1ピクセルにあたります。この lfHeight メンバに格納された値から高さを設定するには、前回行ったピクセル数から twip への単位換算を行ないます。(GetDeviceCaps 関数で1インチ当たりのピクセル数を取得して計算)
フォントの効果として、太字・イタリック体があります。また、 CHOOSEFONT 構造体の Flags メンバに CF_EFFECTS フラグを指定しておいた場合には、打ち消し線・下線も指定できるようになります。太字・イタリック体の設定に関しては、 CHOOSEFONT 構造体と LOGFONT 構造体のどちらからも取得できますが、今回は、 CHOOSEFONT 構造体の nFontType メンバを参照することにします。
; CHOOSEFONT構造体を変数 chfont にとる ; CHARFORMAT 構造体を変数 charfmt にとる ; nFontType メンバは chfont.12 にあたる ; dwEffects メンバは charfmt.2 にあたる if (chfont.12 & 0x0100) { ; BOLD_FONTTYPE タイプを持つ場合 charfmt.2 = charfmt.2 | 0x0001 ; CFE_BOLD を加える(太字) } if (chfont.12 & 0x0200) { ; ITALIC_FONTTYPE タイプを持つ場合 charfmt.2 = charfmt.2 | 0x0002 ; CFE_ITALICを加える (イタリック体) }
下線・打ち消し線の設定は LOGFONT 構造体の lfUnderline メンバと lfStrikeOut メンバを参照します。
; LOGFONT 構造体を変数 logfont にとる ; lfUnderline メンバは logfont.5 の第2バイトにあたる ; lfStrikeOut メンバは logfont.5 の第3バイトにあたる if (logfont.5 & 0x0000FF00) { ; lfUnderlineが指定されている場合 charfmt.2 = charfmt.2 | 0x0004 ; CFE_UNDERLINEを加える(下線) } if (logfont.5 & 0x00FF0000) { ; lfStrikeOutが指定されている場合 charfmt.2 = charfmt.2 | 0x0008 ; CFE_STRIKEOUTを加える(打ち消し線) }
実際にスクリプトを書いてみましょう。前回のスクリプトのうち書式設定の部分を、フォント選択ダイアログボックスを表示するように変更しています。
#include "llmod.as"
objsize winx, 24 : button "フォント変更", *lb_fontdialog
; RICHEDIT.DLLのロード
ll_libload hRtLib, "RICHED32.DLL"
; リッチエディットコントロールの作成
mref bmscr, 67 ; 描画中ウィンドウのBMSCR構造体
classname = "RichEdit"
pm.0 = 0
getptr pm.1, classname
pm.2 = 0
pm.3 = 0x50A00044 ; WS_CHILD | WS_VISIBLE | WS_BORDER
; | WS_VSCROLL | ES_MULTILINE
; | ES_AUTOVSCROLL
pm.4 = 0, 24, winx, winy-24
pm.8 = bmscr.13 ; 描画中HSPウィンドウのハンドル
pm.9 = 0xFF00 ; コントロールID (大きめに指定)
_get_instance pm.10 ; インスタンスハンドル取得
pm.11 = 0
dllproc "CreateWindowExA", pm, 12, D_USER
hEdit = stat ; リッチエディットのハンドル
; テキストサイズの上限の設定
; EM_EXLIMITTEXT メッセージ送信
pm = hEdit, 0x0435, 0
pm.3 = 10 * 1024 * 1024 ; 10Mバイトに設定
sendmsg pm
stop
*lb_fontdialog
; CHOOSEFONT 構造体を変数 chfont にとる
; LOGFONT 構造体を変数 logfont にとる
mref bmscr, 67 ; HSPウィンドウのBMSCR構造体取得
; CHOOSEFONT 構造体
chfont.0 = 60 ; 構造体サイズ(=60)
chfont.1 = bmscr.13 ; ウィンドウハンドル
getptr chfont.3, logfont ; LOGFONT 構造体アドレス
chfont.5 = 0x01000141 ; CF_SCREENFONTS | CF_INITTOLOGFONTSTRUCT
; | CF_EFFECTS | CF_NOVERTFONTS
; フォント選択ダイアログボックスの表示
getptr pm, chfont
dllproc "ChooseFontA", pm, 1, D_COMDLG
if stat == 0 : stop ; キャンセルされた
; CHARFORMAT 構造体を変数 charfmt にとる
dim charfmt, 16
charfmt.0 = 60 ; 構造体サイズ
charfmt.1 = 0xE800000F ; CFM_BOLD | CFM_ITALIC | CFM_UNDERLINE
; | CFM_STRIKEOUT | CFM_FACE | CFM_COLOR
; | CFM_SIZE
charfmt.2 = 0
if (chfont.12 & 0x0100) { ; BOLD_FONTTYPEタイプを持つ場合
charfmt.2 = charfmt.2 | 0x0001 ; CFE_BOLDを加える(太字)
}
if (chfont.12 & 0x0200) { ; ITALIC_FONTTYPEタイプを持つ場合
charfmt.2 = charfmt.2 | 0x0002 ; CFE_ITALICを加える(イタリック体)
}
if (logfont.5 & 0x0000FF00) { ; lfUnderlineが指定されている場合
charfmt.2 = charfmt.2 | 0x0004 ; CFE_UNDERLINEを加える(下線)
}
if (logfont.5 & 0x00FF0000) { ; lfStrikeOutが指定されている場合
charfmt.2 = charfmt.2 | 0x0008 ; CFE_STRIKEOUTを加える(打ち消し線)
}
charfmt.3 = chfont.4 * 2 ; サイズ変換(1/10 point → twip)
charfmt.5 = chfont.6 ; 文字色
peek t, logfont, 23 ; LOGFONT からキャラクタセット取得
poke charfmt, 24, t ; CHARFORMAT にキャラクタセット設定
peek t, logfont, 27 ; LOGFONT からピッチ・ファミリ値取得
poke charfmt, 25, t ; CHARFORMAT にピッチ・ファミリ値設定
sdim fontname, 32
peek fontname, logfont, 28 ; LOGFONT からフォント名取得
poke charfmt, 26, fontname ; CHARFORMAT にフォント名設定
; EM_SETCHARFORMAT メッセージ送信
pm = hEdit, 0x0444
pm.2 = 0x0001 ; SCF_SELECTION
getptr pm.3, charfmt ; CHARFORMAT構造体のアドレス
sendmsg pm
if stat == 0 : dialog "書式の設定に失敗しました。", 1, "エラー"
stop