antenn-a
company profile

MFC航海日記 三十日(アニメートコントロール)

さて、まず初めに言っておきます。

アニメートコントロールの実装に失敗しました!!!

VC4.0時代にサンプルを作った時はできたのに、5.0だと動かない。。。。なんで?

色々試したのだが、やはりできない。 CAnimateCtrl::Play()や、CAnimeteCtrl::Open()がFALSEを返しやがる。 だめだこりゃ・・・

prev


と言うわけで、今回は「自作アニメートコントロール」に挑戦だ!(半ばむちゃくちゃ)

まず、アニメさせる絵を作ってみた(これが一番時間かかった(涙))















prev


ほぅら!リネームしているようにみえるでしょ!(見えないって?俺絵心ないからなあ・・・・(がっくり))

実際はこれとは少し違う。上記のファイルはアニメーションGIFだが、アプリケーションでは BMP ファイルであるし、動かすのはプログラムで動かすので AVI ファイルは用いない。

本当は AVI ファイルでやろうと思ったのだが、時間が無いと言うのとせっかく見つけた AVI ファイルのフォーマットを無くしてしまった為である(ヲイヲイ)

prev


実装方法は非常に簡単である。
タイマーをセットして、一定時間ごとに絵を差し替える。

これでできるはずである。

タイマーのセットの仕方は、非常に簡単なのであるが、一つ不可解な事があった。 タイマー関数の引数並び等はヘルプを参照していただきたい。
void CALLBACK TimerProc( HWND hWnd, UINT nMsg, UINT nIDEvent, DWORD dwTime )
{
    if( NowBmpNum == TotalBmpNum )
       NowBmpNum = 0;
    else
       NowBmpNum++;

    //この関数は静的関数の為、直接メンバー関数をコールする事ができない。
    //ゆえにメインダイアログのポインタを取得する事にする。
    //メインダイアログの取得
    CAnimateDlg* d = (CAnimateDlg*)AfxGetMainWnd();
    ASSERT_VALID( d );

    d->EACtrl.Invalidate();
}

void EAnimateCtrl::StartAction()
{
    TimerID = SetTimer( TIMER_ID, 100, TimerProc );
}

void EAnimateCtrl::EndAction()
{
    KillTimer( TimerID );
}
上記のようにして実装したのだが、デストラクタでEndAction()を呼ぶと処理できない例外でアプリケーションがおっこってしまう。 タイマーはセットしたら殺してやらないといけないはずなのだが、殺そうとするとエラーになってしまう(^^;;;

しかし、次回起動時に同じタイマーIDが取得できる事からどこかで殺されているらしいのだが・・・どこで殺されているかが分からない。

誰かご存知の方御教授ください。

prev


表示ルーチンの方は、以下のようである。

int   NowBmpNum;

void EAnimateCtrl::InitAnimation( short* index, short totalbmpnum )
{
    if( m_pBitmap )
        delete    []m_pBitmap;

    m_pBitmap = new CBitmap[ totalbmpnum ];

    int     i;
    for( i = 0; i < totalbmpnum; i++ )
        m_pBitmap[ i ].LoadBitmap( index[ i ] );

    TotalBmpNum = totalbmpnum;
    NowBmpNum = 0;
}

void EAnimateCtrl::First( CDC& dc )
{
    //初期化ルーチン
    dc.SetBkColor( RGB( 0, 0, 0 ) );
    m_pdcDisplayMemory.CreateCompatibleDC( &dc );
    m_pdcDisplayMemory.SelectObject( m_pBitmap[ 0 ] );
    m_pBitmap[ 0 ].GetObject( sizeof( bm ), &bm );
    m_sizeSource.cx = bm.bmWidth;
    m_sizeSource.cy = bm.bmHeight;
    m_sizeDest = m_sizeSource;
    dc.DPtoLP(&m_sizeDest); 
}

void EAnimateCtrl::OnPaint() 
{
    CPaintDC    dc(this); // 描画用のデバイス コンテキスト

    if( !m_pBitmap )
        return;

    static BOOL FirstFlag = TRUE;

    if( FirstFlag == TRUE ){
        First( dc );
        FirstFlag = FALSE;
    }
    else{
        m_pdcDisplayMemory.SelectObject( m_pBitmap[ NowBmpNum ] );
    }
    //
    dc.StretchBlt( 0, 0, 
                   m_sizeDest.cx, 
                   m_sizeDest.cy, 
                   &m_pdcDisplayMemory, 
                   0, 0, 
                   m_sizeSource.cx, 
                   m_sizeSource.cy, 
                   SRCCOPY
                 );
}

prev


上記のようにして、一応はアニメートするようにはなった。 本来はもっとカスタマイズしたり、デバッグしなければならないのであるが、ひとまずこのままでいけるのでよしとしよう(ほんとか?)

今回のサンプルはここからダウンロードできる。読者の方も是非試してみてはいかがだろうか? バグレポート等お待ちしています(はっきり言って自信ありません)



antenn-a

prev next


antenn-a