Today プラグインサンプルプログラム2 †背景透過 †Today プラグインサンプルプログラムで作ったサンプルでは、ウィンドウクラス登録で指定した黒ブラシで描画された背景を持つアイテムが表示されていました。 というわけで、前回黒かった部分を透過して、壁紙を表示させるようにします。 といっても、WindowsMobileSDKのサンプル等を見ると、WM_ERASEBKGNDを処理して、シェルにTODAYM_DRAWWATERMARKメッセージで壁紙を描いてもらうという処理を行っているようですが、これをしなくても、ウィンドウクラスのhbrBackgroundをNULL指定にするだけで、とりあえずは壁紙が表示されるようです。 恐らく、アイテムの親ウィンドウにWS_CLIPCHILDRENがついていないので、親ウィンドウが描画されるタイミングでアイテム部分まで壁紙が描画されているので、問題なく透けて見えているようです。 実際、NULL指定だけでは、他のアプリを起動、終了させて、再度Today画面が表示された時等に、何も描画されなかったりします。 ちらつきを抑えるという意味では、一旦親ウィンドウが背景を描いてしまうことがある以上、多少のちらつきはあるかもしれないのですが、アイテムの描画としては、ウィンドウクラスではNULLブラシを設定してWM_ERASEBKGNDでは何もせず、WM_PAINT時に裏バッファを用意しておいて、そこにTODAYM_DRAWWATERMARKで背景を描いてもらい、アイテムの描画を行った上で、表画面に描画するのがいいのかもしれませんね。 なのでまずは、WM_ERASEBKGNDで何もしないようにします。 BOOL Today_OnEraseBkgnd( HWND hwnd, HDC hdc ); // WM_ERASEBKGND処理 ウィンドウプロシージャも追加します。 HANDLE_MSG( hwnd, WM_ERASEBKGND, Today_OnEraseBkgnd ); そして、何もせずに、背景を消去したという意味のTRUEを返します。 BOOL Today_OnEraseBkgnd( HWND hwnd, HDC hdc ) { return TRUE; } 次に、WM_PAINTの処理を作り、その中でバックバッファを作成することにしましょう。 縦画面/横画面の切り替わりで、クライアント領域のサイズが変わるはずなので、描画のタイミングでサイズチェックを行えば、問題なく検知できるはずです。 で、ちょっと調べてみたところ、縦横の切替はChangeDisplaySettingsExで行うことが出来、WM_SIZEメッセージとWM_SETTINGCHANGEメッセージで検知して処理するようです。 バックバッファ作成のために、Todayウィンドウクラスに、以下のようなメンバを追加します。 HDC m_hdc; // デバイスコンテキスト HBITMAP m_hOldbmp; // ビットマップハンドル RECT m_rect; // クライアント矩形保存用 それぞれ、表示画面と互換性のあるデバイスコンテキストを保存しておくメンバと、表示画面と互換性のあるビットマップをデバイスコンテキストに関連付けた際に、元々関連付けられていたデフォルトのビットマップが返されるので、それを後で戻すために保持しておくメンバと、サイズ変更を検知するために、作成時のクライアント矩形を覚えておくメンバになります。 バックバッファ作成前に、GetClientRectでクライアント領域を取得し、メンバに保存してある領域とサイズが同じであれば、特に何もしません。 解放と作成の流れは、以下の通り。 // バックバッファ解放 void CTodayWnd::freBkBuffer( void ) { HBITMAP hbitmap = NULL; // ビットマップハンドル if( m_hOldbmp ){ hbitmap = SelectBitmap( m_hdc, m_hOldbmp ); DeleteBitmap( hbitmap ); m_hOldbmp = NULL; } if( m_hdc ){ ::DeleteDC( m_hdc ); m_hdc = NULL; } ZeroMemory( &m_rect, sizeof( RECT )); } // バックバッファ作成 bool CTodayWnd::creBkBuffer( void ) { HDC hdc = NULL; // デバイスコンテキスト HBITMAP hbitmap = NULL; // ビットマップハンドル RECT rect; // クライアント矩形保存用 if( NULL == m_hwnd ){ return false; } // クライアント矩形取得 if( !::GetClientRect( m_hwnd, &rect )){ return false; } if( 0 == memcmp( &m_rect, &rect, sizeof( RECT ))){ // 領域に変化なし return true; } freBkBuffer(); // ウィンドウのデバイスコンテキスト取得 hdc = ::GetDC( m_hwnd ); if( NULL == hdc ){ goto Error; } // コンパチデバイスコンテキスト作成 m_hdc = ::CreateCompatibleDC( hdc ); if( NULL == m_hdc ){ goto Error; } // コンパチビットマップ作成 hbitmap = ::CreateCompatibleBitmap( hdc, rect.right, rect.bottom ); if( NULL == hbitmap ){ goto Error; } // ビットマップの関連付け m_hOldbmp = SelectBitmap( m_hdc, hbitmap ); if( NULL == m_hOldbmp ){ goto Error; } CopyMemory( &m_rect, &rect, sizeof( RECT )); return true; Error: freBkBuffer(); if( NULL != hdc ){ ::ReleaseDC( m_hwnd, hdc ); hdc = NULL; } return false; } 裏画面を作り終わったら、まずはこの裏画面に、透かした背景をシェル側に描いて貰う必要があります。 そして、背景が描かれた裏画面上に、自分で好きなものを描いて、全て描き終わったら、裏画面を表画面に転送という流れになります。 試しに、背景にテキストを書いて、それを表画面に表示する処理を、WM_PAINTに実装してみます。 プロトタイプ宣言は以下のように。 void Today_OnPaint( HWND hwnd ); // WM_PAINT処理 ウィンドウプロシージャも追加します。 HANDLE_MSG( hwnd, WM_PAINT, Today_OnPaint ); 実際の処理は、以下の通り。 void Today_OnPaint( HWND hwnd ) { LPCTodayWnd lpCTodayWnd = NULL; // Todayウィンドウクラス TODAYDRAWWATERMARKINFO tdwmi; // 透かし描画用構造体 PAINTSTRUCT ps; // PAINT構造体 HDC hdc = NULL; // デバイスコンテキスト lpCTodayWnd = ( LPCTodayWnd )::GetWindowLong( hwnd, GWL_USERDATA ); if( NULL == lpCTodayWnd ){ return; } // バックバッファ作成 if( !lpCTodayWnd->creBkBuffer() ){ return; } // 裏画面に背景を描いてもらう ZeroMemory( &tdwmi, sizeof( TODAYDRAWWATERMARKINFO )); tdwmi.hwnd = hwnd; tdwmi.hdc = lpCTodayWnd->getBkDC(); if( !::GetClientRect( hwnd, &tdwmi.rc )){ return; } if( !::SendMessage( ::GetParent( hwnd ), TODAYM_DRAWWATERMARK, 0, ( LPARAM )&tdwmi )){ return; } if( !::ExtTextOut( lpCTodayWnd->getBkDC(), 0, 0, ETO_CLIPPED, NULL, TEXT( "てすと" ), 3, NULL )){ return; } // 裏画面を表画面に転送 ZeroMemory( &ps, sizeof( PAINTSTRUCT )); hdc = ::BeginPaint( hwnd, &ps ); if( NULL == hdc ){ return; } ::BitBlt( hdc, tdwmi.rc.left, tdwmi.rc.top, tdwmi.rc.right, tdwmi.rc.bottom, lpCTodayWnd->getBkDC(), 0, 0, SRCCOPY ); ::EndPaint( hwnd, &ps ); } これで、以下のような表示になるはずです。 背景のデバイスコンテキストの背景透過モードをONにしていないので、テキストの色抜きがされていないですし、フォントの種類も色もデフォルトなので、見栄えは悪いですが……。 テキストを描くくらいでしたら、これで問題ないと思いますが、例えば他の画像を、背景の上にアンチエイリアス付きで描画したいとか、部分Blendしてアニメーションしたいとかなった場合は、表示画面と互換性のあるビットマップではなく、メモリアドレスが取れるフルカラーのDIBSectionを作る等して、ピクセル単位でのBlendをする等、工夫が必要になってくるでしょう。 とりあえず、ここまでのソースをつけておきます。 |