デスクトップキャラクターのアニメーションが崩れる

[戻る]
たにし 2009/08/24(月) 02:19:23
【 開発環境 】
VC2005 / Visual C++ (非MFC) / Windows XP /

お世話になっております。
WEBのサンプルソースを参考にして、デスクトップキャラクターを作成しています。
ウインドウ(Dialog)をBMP画像のリージョンの形になるよう設定して作成しています。

このキャラクターの画像を更新し、アニメーションをさせようと思っているのですが、
再描画前のコマの残像のようなものが残り、キレイにアニメーションできません。


↓ダイアログの作成は下記のようにしています。

CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_TEST), hWnd,(DLGPROC)TestProc);



↑このダイアログのプロシージャでは、
↓下記のようにアニメーションをさせています。


static HBITMAP bmp_koma[2];
static int nNomalNo=0;
static HRGN mas_hRgn;


case WM_CREATE:
    bmp_koma[0] =  LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGE_00));
    bmp_koma[1] =  LoadBitmap(g_hInst, MAKEINTRESOURCE(IDB_IMAGE_01));
    break;


case WM_TIMER://1秒間隔のタイマー
    // アニメのコマ番号を1つ進める
    nNomalNo = (nNomalNo + 1) % 2;
    InvalidateRect(hWnd, NULL, 0); 
    break;


case WM_PAINT:
{
    HBITMAP     hBitmap = NULL;
    BITMAP      bm;
    PAINTSTRUCT ps;
    HDC         dst_hdc, src_hdc;
    HRGN        hRgn_tmp;
    
    // 描画するコマ画像を指定
    hBitmap = bmp_koma[nNomalNo];

    GetObject(hBitmap, sizeof(BITMAP), &bm);
    hRgn_tmp = CreateRgnFromBmp(hBitmap, (UINT)-1); //画像からリージョンを作成す
る自作関数
   
    dst_hdc = BeginPaint(hWnd, &ps); // 描画開始
    {
        src_hdc = CreateCompatibleDC(dst_hdc);    // HDCのコピーを作成
        SelectObject(src_hdc, hBitmap);        // 新しい画像をHDCに設定
        BitBlt(dst_hdc, 0,0, bm.bmWidth, bm.bmHeight, src_hdc, 0,0, 
SRCCOPY); // 新しいHDCを元のHDCに転送する
        DeleteDC(src_hdc);
    }
    EndPaint(hWnd, &ps);        // 描画終了


    SetWindowRgn(hWnd, hRgn_tmp, TRUE); // 新しいリージョンを設定
    if (mas_hRgn){
        DeleteObject(mas_hRgn);// 古いリージョンを開放
    }
    mas_hRgn = hRgn_tmp;       
    SetProp(hWnd, _T("region"), mas_hRgn);

}
return FALSE;




CreateDialog()で作成したウインドウでは先述の通り
キレイにアニメーションできないのですが、
↓下記のように作成したウインドウでは、キレイにアニメーションが出来ています。

 CreateWindowEx(
         WS_EX_TOPMOST | WS_EX_TOOLWINDOW, szWindowClass
       , NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 203, 213
       , NULL, NULL, hInst, NULL
  );

なぜCreateDialog()で作成したウインドウでは、キレイにアニメーションができないので
しょうか。
アドバイスのほど宜しくお願い致します。

subaru 2009/08/24(月) 10:01:22
キレイにアニメーションできない理由はわかりませんが、
再描画の度にリージョンの作成と設定まで行う必要はありますか?
タイマーが1秒間隔でもWM_PAINTは1秒間隔で発生するわけではありません。

特に理由がないなら、リージョンの作成と設定はWM_TIMERの方で行って
WM_PAINTは描画のみにしておくべきでしょう。

またリージョンが2つしかないのであれば、あらかじめ作成しておいて
タイマーで切り替えるだけの方が効率がよさそうです。

ryo 2009/08/24(月) 12:41:11
>CreateDialog(g_hInst, MAKEINTRESOURCE(IDD_TEST), hWnd,(DLGPROC)TestProc);
ここでオーナーウィンドウとして引き渡してるのは「hWnd」は誰?

> CreateWindowEx(
>         WS_EX_TOPMOST | WS_EX_TOOLWINDOW, szWindowClass
>       , NULL, WS_POPUP, CW_USEDEFAULT, CW_USEDEFAULT, 203, 213
>       , NULL, NULL, hInst, NULL
>  );
こっちでは、オーナーウィンドウはNULL(デスクトップ?)指定になってるようですが

この違いじゃないかな

実験したわけじゃないので単なる予想ですが

残像が残る
↓
前のコマを消してない
↓
消す処理も見当たらない
↓
ウィンドウの持つ背景を消すデフォルトの処理任せだがやってくれない
↓
下にあたるウィンドウの指定がおかしい?

って感じがします

ロマ 2009/08/24(月) 17:56:36
想像ですが

1)ダイアログプロシージャがFALSEを返しているのでダイアログのWindowProcが呼ばれる
2)ダイアログのWindowProcのWM_PAINTハンドラが実行される
3)提示されたWM_PAINTハンドラのSetWindowRgn()で領域が広がった場合は
 この領域は無効領域なので、ダイアログのWindowProcのWM_PAINTハンドラは作業する

という流れのような気がします

# case WM_CREATEはWM_INITDIALOGのまちがいですか ?

たにし 2009/08/24(月) 22:20:50
[[解決]]
皆様、早速のレスありがとうございます。

結論から言いますと、ロマさんの助言から下記の通りコードを変更することで
残像が消え、キレイにアニメーションされるようになりました。

<変更前>
   case WM_PAINT:

      /* 〜処理〜 */

      return FALSE;


<変更後>
   case WM_PAINT:

      /* 〜処理〜 */

      return TRUE;



> subaru さん

仰る通り、WM_TIMERでリージョンの作成と設定を行ったほうが
効率がよさそうですね。とても参考になります。
ご助言どうもありがとうございます。


> ryo さん

CreateDialog()に渡しているのはメインウインドウのハンドルとなっています。
記載していなかったので恐縮ですが、メインウインドウの子ウインドウとして
マスコットキャラクターとなるダイアログを作成しております。
ご助言どうもありがとうございます。


> ロマ さん

勉強不足で、無効領域というものがよく理解できていませんでした。
ご助言どうもありがとうございました。
case WM_CREATE は正しくは case WM_INITDIALOG でした。

古いスレッドには追加発言できません。