#pragma twice

KAB-studio > プログラミング > #pragma twice > 141 Version 7.21 タイマーの限界

#pragma twice 141 Version 7.21 タイマーの限界

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

 Version 7.21
タイマーの限界

今回はこれまでのまとめみたいな感じ
いよいよアニメーション!
の幻想をうち砕くっていうか
げげ
まずは、 Ver 7.18 ( No.138 ) のタイマーの機能と、
Ver 7.19 ( No.139 ) のランダムを組み合わせてみます
ほいほい
まずは、ダイアログが表示される時に呼ばれる 
CAnimeDlg::OnInitDialog() から

BOOL CAnimeDlg::OnInitDialog()
{
// 略。
    // TODO: 特別な初期化を行う時はこの場所に追加してください。
    ::SetTimer
        ( GetSafeHwnd()
        , 100   // タイマー ID 。
        , 125   // タイマーのインターバル。
        , NULL
        );

    return TRUE;  // TRUE を返すと(略)。
}

この API でタイマーがオンになるんだよね
そうそう。次は、そのタイマーをオフにする部分

void CAnimeDlg::OnBDraw() 
{
    ::KillTimer( GetSafeHwnd(), 100 );
}

これも 7.18 のと同じね
最後に本命、タイマーから呼ばれる関数

void CAnimeDlg::OnTimer(UINT nIDEvent) 
{
    time_t lTime_t;
    time( &lTime_t );
    srand( lTime_t );

    // ランダムに3色作成。
    const int iRed = rand() % 256;
    const int iGreen = rand() % 256;
    const int iBlue = rand() % 256;
    // その3色でブラシを作ります。
    HBRUSH hBrush
        = ::CreateSolidBrush( RGB( iRed, iGreen, iBlue ) );

    RECT stRect;
    ::GetClientRect( m_cCanvasStatic.GetSafeHwnd(), &stRect );
    HDC hDC = ::GetDC( m_cCanvasStatic.GetSafeHwnd() );
    ::FillRect( hDC, &stRect, hBrush );
    ::DeleteObject( hBrush );
    ::ReleaseDC( m_cCanvasStatic.GetSafeHwnd(), hDC );

    CDialog::OnTimer(nIDEvent);
}

おおっ、ランダムが使われてる!
 7.18 では少しずつ色を変えていったけど、今回はランダムで色を変えて
いきます
ってことは、その時使った m_iRed ってメンバ変数は?
もう必要なし
あらま。あれ? % って何?
これは【割り算の余り】を計算する演算子。 rand() ってテキトーな整数
値が出てくるでしょ
うん、出てきた
でも、 RGB に使えるのは 0 から 255 までの整数値。そこで % を使いま
す。整数値を割った時の余りは、 0 から割る数 - 1 の間に入るから
 256 で割った余りなら、必ず 0 から 255 の間に入るわけね
これは乱数を使う時によく使う方法だから憶えておいてね。じゃ、これを
試してみて
ほい、ビルドして実行! ……なんか……
ものすごーく紙芝居っぽい感じでしょ
紙芝居って言い得て妙ねー
言い得て妙、ってのもなんか……
ってゆーか、なんでこんなに変なの? だって、タイマーの間隔って 
SetTimer() の第3引数だよね
そう、単位はミリセカンド、つまり1秒の千分の1
ってことは 125 は8分の1秒だよね。なんでこんなにパラパラな感じな
の?
それは、タイマーってものの性質と、メッセージそのもののシステムを理
解しないと
な、なんか複雑そう……
うん、その辺は複雑。今年はその方向へと掘り下げていく1年になりそう
かな
新年の抱負にしてはなんか……
とりあえず今回は、どんな感じになってるかって説明だけ。実際に見てい
くのは少し後ってことで
はーい
まずメッセージの復習。 Ver 5.27 ( No.092 ) を読み返して
メッセージって SendMessage() で送れるんだよね
その送られたメッセージはウィンドウプロシージャで受け取るってことも
確認してね
ほい。次の Ver 5.28 ( No.093 ) もその関係だよね
そうそう、イベントとメッセージの関係。で、今回の復習だけど

BOOL CAnimeDlg::OnInitDialog()



void CAnimeDlg::OnPaint() 



void CAnimeDlg::OnBDraw() 



void CAnimeDlg::OnDrawItem
    (int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct) 



void CAnimeDlg::OnTimer(UINT nIDEvent) 

も、ぜーんぶイベント
どゆこと?
たとえば CAnimeDlg::OnInitDialog() は、ダイアログが作られて表示さ
れるってイベントが起きた時に、ウィンドウプロシージャに 
WM_INITDIALOG ってメッセージが送られてきて、それを MFC が受け取って 
CAnimeDlg::OnInitDialog() を呼び出すって仕組みになってます
送られてくるって、どこから?
ウィンドウズそのものから
ウィンドウズが SendMessage() するような感じ?
そんな感じ。ウィンドウズは、どんなちっちゃなイベントが起きた時で
も、そのイベントに合わせてメッセージを送ってきます。同じように、他
のメンバ関数も
メッセージが送られてきて呼ばれる?
そう。 CAnimeDlg::OnPaint() は WM_PAINT は〈描画して欲しい〉って度
に送られてきて、それを MFC のウィンドウプロシージャが受け取って 
CAnimeDlg::OnPaint() を呼び出すって仕組みになってます
再描画ってイベントでメッセージが送られてくるわけね
今はこの、メッセージを受け取って、そこからメンバ関数が呼ばれるま
でって部分が見えてないからよく分かんないだろうけど、いつかそれが見え
ればどういうことか分かってくると思うから
いつかなぁ
近いうちに教えるから大丈夫。で、タイマーの話。 SetTimer() を呼ぶ
と、一定時間ごとにウィンドウズが WM_TIMER ってメッセージを送ってくる
ようになります
〈一定時間〉がイベントってことね
そゆこと。ところが、このメッセージは特別で、他のメッセージより優先
度が低いんです
 WM_PAINT とかよりも?
そう、そういうメッセージが WM_TIMER の後ろに控えている場合には、 
WM_TIMER を無視して他のメッセージを先に受け取るような仕組みになって
るんです
あ! だからこんなにがたがたになるんだ!
そゆこと。これは、ウィンドウズのタイマーの仕様だから、どうしようも
ないかな
そんなー。じゃあこのアニメーションってできないの?
今はね。将来的にはできるようになってもらうけど。ちょっとかじってみ
ようか。 CAnimeDlg::OnInitDialog() の前にこの関数を置いて

unsigned int _stdcall DrawThread( void *p_pvPara )
{
    time_t lTime_t;
    time( &lTime_t );
    srand( lTime_t );

    HWND hCanvasWnd = (HWND)p_pvPara;
    int iRed;
    int iGreen;
    int iBlue;
    HBRUSH hBrush;
    RECT stRect;
    ::GetClientRect( hCanvasWnd, &stRect );
    HDC hDC = ::GetDC( hCanvasWnd );

    while( 1 )
    {
        iRed = rand() % 256;
        iGreen = rand() % 256;
        iBlue = rand() % 256;
        hBrush = ::CreateSolidBrush( RGB( iRed, iGreen, iBlue ) );
        ::FillRect( hDC, &stRect, hBrush );
        ::DeleteObject( hBrush );

        Sleep( 50 );
    }

    ::ReleaseDC( hCanvasWnd, hDC );
    return TRUE;
}

普通の関数だね。あ! これって Ver 7.18 ( No.138 ) の無限ループと
やってること同じじゃん! 嫌! また止まっちゃう!
これが止まらないんだよね
へ?
あ、あと CAnimeDlg::OnInitDialog() の SetTimer() のとこを

BOOL CAnimeDlg::OnInitDialog()
{
// 略。
    // TODO: 特別な初期化を行う時はこの場所に追加してください。
    HANDLE hCoreThread;
    DWORD dwCoreThreadId;
    hCoreThread
         = (HANDLE)_beginthreadex
                ( 0, 0, DrawThread
                , ( void * )( m_cCanvasStatic.GetSafeHwnd() )
                , 0, ( unsigned int * )( &dwCoreThreadId ) 
                );

    return TRUE;  // TRUE を返すと(略)。
}

に置き換えて
うわ、アンダーバー付いてる謎な関数……とりあえずビルドして実行。お
おっ! ちかちかしつつもちゃんといろんな色が!! かなり早い!
これは【マルチスレッド】って機能。少し先になるけど、これもいつか教
えるからねー
うん、とりあえずやり方はあるってことが分かっただけでもいいかも

/*
    Preview Next Story!
*/
ってゆーか、こういう方法って教えてもらわないと分かんないよね
そのために教えてるんだけど
はいはいはい
あ、そういう意味じゃなくて、そうなんだけど
??
火美ちゃんも自分で調べられないとね、って話
調べられるのかなぁ
というわけで次回
< Version 7.22 情報の見つけ方 >
につづく!
実は次回、デバイスコンテキスト編最終回
げ! なにいきなり!
 
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
RSSに登録
del.icio.us 登録する
Yahoo!ブックマーク 詳細を表示 users
livedoorクリップ 詳細を表示 livedoorクリップ ブックマーク数
はてなブックマーク 詳細を表示 はてなブックマーク ブックマーク数
 
このページは、Visual C++ 6.0を用いた C++ 言語プログラミングの解説を行う#pragma twiceの一コンテンツです。
詳しい説明は#pragma twiceのトップページをご覧ください。