#pragma twice

KAB-studio > プログラミング > #pragma twice > 137 Version 7.17 オーナードローでカッコヨク!

#pragma twice 137 Version 7.17 オーナードローでカッコヨク!

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

 Version 7.17
オーナードローでカッコヨク!

今回はちょっと面白いことをしてみましょう
面白いこと?
っていうか、ホントはデバイスコンテキスト自体結構面白いものなんだけ
どね。画面に描画できるわけだから
アプリに好きなよーに絵が描けるわけだもんね
今回教える【オーナードロー】は、デバイスコンテキストが使いたくなる
ような仕組みのひとつ。ダイアログに IDC_B_DRAW ボタンがあるでしょ
うんある。【描く!】って書いたの
これを【描く!】じゃなく、ちょっと派手にすることができるんです
それがオーナードローってヤツなんだ
または【オーナー描画】って言うのだけど、ここではオーナードローで統
一するね
オーナー描画って、漢字が分からない文字だけひらがなにしてるみたいで
なんか変……
オーナードローの、オーナーは【持ち主】、ドローは【描く】
ビルのオーナーとか言うもんね
そのビルに当たるのが、ダイアログ
ボタンを持ってるのはダイアログ、ってことね。ってことは、そのダイア
ログがボタンを描く?
そゆこと。普通はボタンが自分自身を描くんだけど、そうじゃなくてボタ
ンの持ち主のダイアログがボタンを描く、それがオーナードロー
……なんか難しそうなんだけど……
でもかなり簡単。特にボタンはね。とりあえずやってみようか。まずはク
ラスウィザードを開いて。メニューの【表示】から【 ClassWizard 】を選
んで
ダイアログ出たよ
【メッセージマップ】のページを開いて、【クラス名】は CAnimeDlg 、
【オブジェクト ID 】も CAnimeDlg にして
ほいほいほい
メッセージの中から WM_DRAWITEM を選んで、右上の【関数の追加】を押
してから【コード編集】を押すと
 CAnimeDlg::OnBDraw() の下にメンバ関数ができた

void CAnimeDlg::OnDrawItem
    (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

まずはこのメンバ関数が呼ばれるかどうか確認しましょう

void CAnimeDlg::OnDrawItem
    (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    TRACE( "Hit!\n" );
    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

んじゃビルドして実行
……
…… Hit! って出ないよ?
うん出ないよ
なんですとー!?
オーナードローは持ち主が描くわけだけど、そのためには描かれるもの、
つまりボタンの方から〈描いていいよ〉って許可しないといけないんです
あー、勝手に描けないんだ
そこで、ボタンの方で許可するようにします。ダイアログを閉じてから、
ダイアログエディタを開いて IDC_B_DRAW のプロパティを開いて
右クリックからプロパティっと
プロパティの【スタイル】ページに
【オーナー描画】がある! これオンにすればいいんだよね
そうそう。それでビルドして実行してみて
ほい。 Hit! って出た! げ、でもボタンが消えた!
消えたんじゃなくて、【描く!】とか、立体的に見せる縁とかも描かれな
くなっただけ。 CAnimeDlg::OnBDraw() に TRACE() でも置いて
この辺にボタンあるかなーってとこで押すと、ちゃんと TRACE() のが出
てくるね。見えてないだけなんだ
というわけで、見えるようにしましょう。そのためのメンバ関数が
CAnimeDlg::OnDrawItem() 。このメンバ関数は、 WM_DRAWITEM ってメッ
セージが送られてきた時に呼ばれるメンバ関数……
……
……つまり、ボタンが押された時に CAnimeDlg::OnBDraw() が呼ばれるよ
うに、ボタンの描画が必要な時に呼ばれるメンバ関数
描画が必要な時っていうと、 CAnimeDlg::OnPaint() みたいな感じ?
ほとんど同じ。ただタイミングとか違う部分も多いけどね。そうそう、 
CAnimeDlg::OnPaint() に前に追加したのは消しちゃっていいから
続き物って感じで教えないね
プログラムは小さく小さく、が重要だからね。と、それは置いといて、実
際にボタンを描画してみましょう。まずボタンの ID が第1引数の nIDCtl 
に入ってるからそれを確認
ボタンの ID ってことは、 IDC_B_DRAW だね。でもこれって何のため?
いくつもボタンをオーナードローにしちゃったら
そっか、それぞれ別の描画しなきゃいけないから
そのためのチェックね。で、ボタンのデバイスコンテキストが第1引数の
lpDrawItemStruct の hDC メンバ変数に入ってます
 LPDRAWITEMSTRUCT って初見
頭の LP は?
ポインタの印だね。それ取ると、 DRAWITEMSTRUCT 
これが構造体になってて、オーナードローに必要な情報が全部入ってるか
ら、これを使って描画すればオーケー
 BeginPaint() とか GetDC() とか
の準備や後片付けは必要ないから。このメンバ関数が呼ばれる前に準備さ
れてるってことかな
便利ねー
それではやってみましょう

void CAnimeDlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    // ここから追加。
    if( nIDCtl == IDC_B_DRAW )
    {
        HBRUSH hBrush;
        hBrush = ::CreateSolidBrush( RGB( 0, 0, 255 ) );
        ::FillRect
            ( lpDrawItemStruct->hDC
            , &( lpDrawItemStruct->rcItem )
            , hBrush 
            );
        ::DeleteObject( hBrush );
    }
    // 追加ここまで。
    
    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

 nIDCtl がそのボタンの ID か調べて、そうならボタンを塗り潰し?
 DRAWITEMSTRUCT::hDC にボタンのデバイスコンテキストが入ってて、
DRAWITEMSTRUCT::rcItem はボタンの四角が入ってる RECT 構造体だから
あとはいつもの塗りつぶしね。 FillRect() の第2引数が分かりにくいけ
ど……
前も言ったけど、これは lpDrawItemStruct-> の部分は無視するのがコ
ツ。だから &rcItem と同じ
 Ver 6.02 ( No.102 ) の話ね。んじゃビルドして実行。を! ボタンが
真っ青!
こういうふうに青く塗りつぶせるわけです。これは無味簡素だけど
がんばれば好きなようなボタンが描けるわけねー。なんかすごい
ま、実際にはここからの方が大変かもね
でもさ、ボタンの枠まで消えちゃうってちょっとビックリかも。だって、
これじゃボタン押したのわからないじゃない
そうじゃなくて、ボタン押した時にはボタン押した時の描画をしなきゃい
けないわけ。ボタンはそうだったわけだから
ボタンを押したらへこむのは、ボタンがへこんだように見えるように描い
てた!
そういうこと。だからオーナードローのときも
へこんだらへこんだように見せなきゃいけない! って、そんなことでき
るの?
もちろん。 DRAWITEMSTRUCT のリファレンスを読むと
色々パラメーターがあるんだね
押されたかどうかは itemState メンバ変数を調べればわかります。この
中の ODS_SELECTED ってビットフラグが立ってたら〈押されてる〉状態。
ビットフラグ調べる方法って憶えてる?
う”
 == の代わりに & で比較すればいいから。 Ver 4.05 ( No.055 ) を参考
にね
普段使わないと忘れちゃうね……
というわけで使ってみましょう

void CAnimeDlg::OnDrawItem
    (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
    // ここから追加。
    if( nIDCtl == IDC_B_DRAW )
    {
        HBRUSH hBrush;
        if( lpDrawItemStruct->itemState & ODS_SELECTED )
        {
            hBrush = ::CreateSolidBrush( RGB( 255, 0, 0 ) );
        }
        else
        {
            hBrush = ::CreateSolidBrush( RGB( 0, 0, 255 ) );
        }

        ::FillRect
            ( lpDrawItemStruct->hDC
            , &( lpDrawItemStruct->rcItem )
            , hBrush 
            );
        ::DeleteObject( hBrush );
    }
    // 追加ここまで。
    
    CDialog::OnDrawItem(nIDCtl, lpDrawItemStruct);
}

んー長いけど、さっきの DRAWITEMSTRUCT::itemState に ODS_SELECTED 
が入ってるか調べてそれで……ブラシの色を変えてる!
 ODS_SELECTED が含まれてる、つまりボタンが押されてる時は赤色、それ
以外は青色
んじゃ実行。おお!! ボタン押すと赤くなる!
こうなるとボタンらしくなるでしょ
なるなる! っつーかこれなんかカッコイイ!
だねー。で、最後に重要なこと
……またミスとか?
違います。ここで重要なのは、こういうオーナードロー的なことを、普段
のボタンもしてるってこと
うん、それはさっき聞いた
そして、ボタンもウィンドウの一種。つまり、ウィンドウを作って、
CAnimeDlg::OnPaint() や CAnimeDlg::OnDrawItem() が呼ばれたときにボタ
ンらしく描画すれば
ボタンになる? ってことは、あたしがボタン作れる!?
将来的には作れるようになってもらうし、ウィンドウズのボタンだって所
詮は
げ、出た。つまりフツーのプログラマーが作ったもんだって言いたいんで
しょ?
そゆこと。こういう、元々存在するシステムのものっていうのはすごいも
のに見えるけど、でもそうじゃないんだってことは忘れないでね
はいはいはい、耳にたこができますよーだ

/*
    Preview Next Story!
*/
何かすると呼ばれるって多いよね
うん、そうしないと CPU が休めないから
げ、これって CPU が楽をするためのシステム!? ダメくさい!
それがね、 CPU が暇じゃないと全部のアプリを見て回れないんだよね
なになに、じゃぁ暇っていうのはいいことなの?
必要不可欠。というわけで次回
< Version 7.18 タイマーで止めない! >
につづく!
暇は重要だよ
えー、暇ってなんかヤダ!
若いねー
水希ちゃんじじくさ!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。