#pragma twice

KAB-studio > プログラミング > #pragma twice > 133 Version 7.13 フォントを変えよう!

#pragma twice 133 Version 7.13 フォントを変えよう!

前のページへ 表紙・目次へ 次のページへ

 Version 7.13
フォントを変えよう!

前回文字を書いてみたから、今度はフォントを変えてみましょう
フォントってみんちょーとかゴシックとかそういうの?
そういうの。フォント変えるだけで結構違ってくるからねー
うん、ちょっと楽しみ
と、いきなりだけどちょっと難しそうなのから

void CAnimeDlg::OnBDraw() 
{
    HDC hCanvasDC = ::GetDC( m_cCanvasStatic.GetSafeHwnd() );

    // フォントの情報を作成。
    LOGFONT stLogFont;
    stLogFont.lfHeight = 100;
    stLogFont.lfWidth = 10;
    stLogFont.lfEscapement = 0;
    stLogFont.lfOrientation = 0;
    stLogFont.lfWeight = FW_NORMAL;
    stLogFont.lfItalic = FALSE;
    stLogFont.lfUnderline = FALSE;
    stLogFont.lfStrikeOut = FALSE;
    stLogFont.lfCharSet = SHIFTJIS_CHARSET;
    stLogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;
    stLogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;
    stLogFont.lfQuality = DEFAULT_QUALITY;
    stLogFont.lfPitchAndFamily = DEFAULT_PITCH | FF_SWISS;
    strcpy( stLogFont.lfFaceName, "MS 明朝" );

    // フォントの作成。
    HFONT hFont = ::CreateFontIndirect( &stLogFont );

    // フォントの入れ替え。
    HFONT hOldFont = (HFONT)::SelectObject( hCanvasDC, hFont );

    // 文字列を書きましょう。
    const char pchText[] = "あいうえお";
    ::TextOut( hCanvasDC, 0, 0, pchText, strlen( pchText ) );

    // 後片付け。
    ::SelectObject( hCanvasDC, hOldFont );
    ::DeleteObject( hFont );
}

う、うわ! なんか大変そう!!
1行目はいつものデバイスコンテキストの取得。そのあとがね
 LOGFONT ってのの変数作って……構造体? これ
そう、フォントの情報を格納するための構造体
フォントの情報……
ちょっと混乱するかもしれないけど、一般的に言う〈フォント〉とは別な
んだよね。一般的なフォントは、ウィンドウズフォルダの中の FONTS フォ
ルダに入ってるのでしょ
そうそう、 MS ゴシックとかみんちょーとか。あ、上の見ると
【MS 明朝】ってあるけど
デバイスコンテキスト関係の〈フォント〉は、一般的なフォント、つまり
MS 明朝とかだけじゃなくて、これから書く文字の高さや幅、その他諸々
もデータとして持ってるものなんです
つまり、どういう文字を書くか、っていうのがデータとして入ってる……
それが LOGFONT なのね
そゆこと。たとえば LOGFONT::lfHeight は書く文字の高さ
あ、そういえば実行してなかった。ほい。うわ! 高!
これを小さくすれば低くなるし、 LOGFONT::lfWidth を増やせば
うわ、太! あ、はみでちゃった
 Ver 7.11 ( No.131 ) のクリッピング使えば
はみ出るの防げる!
ま、この辺はただの組み合わせだからなんとでもなるかな
他のパラメーターは?
……適当に試してみて
げっ、テキトー!
僕自身、全部知ってるわけじゃないんだよね
じゃあパラメーターとかどうやって決めてるの?
検索して探してきたのを適当に
げ、マジで適当なの!?
そうだよ。正直な話、 API は細かいことができる分、こういうふうにパ
ラメーターが細かい場合が多いんだよね。だから、全部憶えていったらキリ
ないから
必要になったら調べて使う?
そゆこと。必要なとこだけ憶えるか、調べるか。たとえば、いわゆるフォ
ント決めるのが LOGFONT::lfFaceName だとか
 strcpy() って文字列コピーするのだね
 Ver 5.07 ( No.072 ) でやったね。 LOGFONT::lfFaceName は要素数 32 
の配列になってるから、ここに使いたいフォント名をコピーすれば
そのフォントで出るわけね。確かにみんちょーになってる
注意したいのは、ホントに正確にフォント名を指定しなきゃダメってこ
と。たとえば "MS 明朝" 
そういえば…… "MS" は大きくて、間のスペースは小さいのなんだね
これは正確にしないとダメだから
厳しい……
それに、PCによって入ってるフォント違うから、こういう決め打ちがで
きるのはMS 明朝とかくらい
隷書体とか普通入ってないもんね
ってゆーか使わないし……。ちなみにフォント選ぶんなら

void CAnimeDlg::OnBDraw() 
{
    CFontDialog cFontDlg;
    cFontDlg.DoModal();
}

お、フォントダイアログ!
 API なら ChooseFont() ね。デフォルトはMS 明朝にして、あとはユー
ザーに選んでもらってカスタマイズ、っていうのが基本かな
なんかそうなってくると難しくなりそうねー
規模が大きくなるからね。話を戻して、別に LOGFONT に必要なパラメー
ター入れただけじゃダメで、ペンやブラシみたく、フォントも GDI のひと
つだから
作らなきゃいけない。そのための API が CreateFontIndirect() ね
この API で、 GDI のフォントがウィンドウズシステムの中に作られて、
それを操作するハンドルが HFONT として返ってくるから
……一応確認するけど、これしても、いわゆるフォントが増えたりはしな
いんだよね
もちろん。 FONTS フォルダ見ても増えたりしてないからね
それとは別物なんだもんね
で、あとはいつもと同じ。デバイスコンテキストに SelectObject() で持
たせて、前回使った TextOut() で文字列を出力
すると、今持ってるフォントで文字を書くわけね
あとはまた元に戻して、今作ったフォントを削除
この辺のルールもいつもと同じね
ま、ここでのポイントは、 API と複雑なパラメーターは切っても切り離
せない
だから全部憶えないで、必要な時に必要なのだけ調べて、あとは他のを流
用、ね
そゆこと。じゃ、次のステップに移りましょう。今はフォントを一から
作ったけど、実際には〈高さだけ増やしたい〉とか〈いわゆるフォントだけ
変えたい〉ってことの方が多いと思うんだよね
そこまでじゃなくても、デフォルトのパラメーターとか必要そう
というわけで、 IDC_S_CANVAS のフォント情報を取得してみましょう

void CAnimeDlg::OnBDraw() 
{
    HDC hCanvasDC = ::GetDC( m_cCanvasStatic.GetSafeHwnd() );

    // フォントのハンドルを取得。
    HFONT hCanvasFont
         = (HFONT)::GetCurrentObject( hCanvasDC, OBJ_FONT );

    // フォントの情報を取得。
    LOGFONT stLogFont;
    ::GetObject( hCanvasFont, sizeof( stLogFont ), &stLogFont );

    // フォント名の表示。
    TRACE( "%s\n", stLogFont.lfFaceName );
    // System
}

んーっと、1行目はいつものデバイスコンテキストを取るヤツね。次の行
の GetCurrentObject() は初めて見る API だね
この API は、デバイスコンテキストが持ってる GDI を取得するためのも
の。簡単に言えば、 SelectObject() の戻り値と同じ
あー、つまり交換しないで、それまで持ってたのを取得するならこの API 
ってわけね
そゆこと。で、次に LOGFONT を用意して、そこに hCanvasFont が持って
るフォント情報をコピーします
それを入れてるのが GetObject() みたいね
そう、この API で hFont が持ってるフォントのデータを stLogFont に
コピーします
で、フォント名が stLogFont.lfFaceName に入ってるからそれを出してる
わけね。でも System って?
システム、つまりウィンドウズが内部に持ってるシステムフォントって意
味。ちょっとこれじゃ分かりにくいよね
さっきの時も、 System ってすればシステムのに?
うん。こうすれば【画面のプロパティ】で指定したのが出るから。あ、あ
と、実際に【画面のプロパティ】で指定したフォントを取得する場合には
SystemParametersInfo() って API を使えばいいから
いいから、ってさらって言うけど、これ使うの難しそう……
だろうねー。ま、それは先の話って事で
まとめると、さっきの逆だよね
さっきは LOGFONT にデータ入れて、CreateFontIndirect() でフォント
作って、そのときもらった HFONT を SelectObject() に渡してデバイスコ
ンテキストに持たせました
今度は GetCurrentObject() で HFONT をもらって、 GetObject() で 
LOGFONT にデータを入れてもらえば、どういうフォントを持ってるか分かる
わけね
そういうこと。じゃ、最後にこのフォントデータを元に別のフォントを
作ってそれで文字を書いてみましょう

void CAnimeDlg::OnBDraw() 
{
    HDC hCanvasDC = ::GetDC( m_cCanvasStatic.GetSafeHwnd() );

    HFONT hCanvasFont
        = (HFONT)::GetCurrentObject( hCanvasDC, OBJ_FONT );
    LOGFONT stLogFont;
    ::GetObject( hCanvasFont, sizeof( stLogFont ), &stLogFont );

    // フォントの変更。
    strcpy( stLogFont.lfFaceName, "MS 明朝" );

    HFONT hFont = ::CreateFontIndirect( &stLogFont );
    HFONT hOldFont = (HFONT)::SelectObject( hCanvasDC, hFont );

    const char pchText[] = "あいうえお";
    ::TextOut( hCanvasDC, 0, 0, pchText, strlen( pchText ) );

    ::SelectObject( hCanvasDC, hOldFont );
    ::DeleteObject( hFont );
}

んーと……あ、結局は LOGFONT にコピーしてもらって、それのフォント
名書き換えてるんだね
そうすれば LOGFONT のほとんどのパラメーターは IDC_S_CANVAS のフォ
ントのまま、フォント名だけが明朝
それを CreateFontIndirect() で新しいフォントとして作って、あとは入
れ替えとかね。あれ? いちいち作り直さなきゃいけないの?
そうみたいだね。パラメーター変えるだけって機能はないみたい。だか
ら、作って削除して、って繰り返さないとね
面倒ねー

/*
    Preview Next Story!
*/
なんかデバイスコンテキストまわりって面倒
これからどんどん面倒になってくるよ
げ! そなの?
ハンドルがどんどん増えてくるからね
増えるくらいなんとかなんない?
プログラムの複雑さはデータ数の二乗に比例するからねぇ
げげげ!
それを何とかしないとね
なんとかねぇ
というわけで次回
< Version 7.14 ハンドルの管理 >
につづく!
あ、データ数の二乗って全然根拠ないから
ないんかい!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。