- 追加された行はこの色です。
- 削除された行はこの色です。
#norelated
#contents
* Today プラグインサンプルプログラム2 [#xa500017]
** 背景透過 [#ofd9e8e8]
[[Today プラグインサンプルプログラム]]で作ったサンプルでは、ウィンドウクラス登録で指定した黒ブラシで描画された背景を持つアイテムが表示されていました。~
この上に色々描いていってもいいのですが、せっかくToday画面には壁紙が表示されているので、その壁紙の上に色々表示させたいですよね。~
というわけで、前回黒かった部分を透過して、壁紙を表示させるようにします。~
といっても、WindowsMobileSDKのサンプル等を見ると、WM_ERASEBKGNDを処理して、シェルにTODAYM_DRAWWATERMARKメッセージで壁紙を描いてもらうという処理を行っているようですが、これをしなくても、ウィンドウクラスのhbrBackgroundをNULL指定にするだけで、とりあえずは壁紙が表示されるようです。~
恐らく、アイテムの親ウィンドウにWS_CLIPCHILDRENがついていないので、親ウィンドウが描画されるタイミングでアイテム部分まで壁紙が描画されているので、問題なく透けて見えているようです。~
ただ、なんらかの要因で親ウィンドウの更新がされずに、アイテム内部の描画だけが必要になった時には、WM_ERASEBKGNDかWM_PAINTを処理して、その中で親ウィンドウに壁紙の描画を依頼する必要があると思われます。~
ちらつきを抑えるという意味では、一旦親ウィンドウが背景を描いてしまう以上、多少のちらつきはしょうがないのですが、アイテムの描画としては、ウィンドウクラスではNULLブラシを設定してWM_ERASEBKGNDでは何もせず、WM_PAINT時に裏バッファを用意しておいて、そこにTODAYM_DRAWWATERMARKで背景を描いてもらい、アイテムの描画を行った上で、表画面に描画するのがいいのかもしれませんね。~
実際、NULL指定だけでは、他のアプリを起動、終了させて、再度Today画面が表示された時等に、何も描画されなかったりします。~
ちらつきを抑えるという意味では、一旦親ウィンドウが背景を描いてしまうことがある以上、多少のちらつきはあるかもしれないのですが、アイテムの描画としては、ウィンドウクラスではNULLブラシを設定してWM_ERASEBKGNDでは何もせず、WM_PAINT時に裏バッファを用意しておいて、そこにTODAYM_DRAWWATERMARKで背景を描いてもらい、アイテムの描画を行った上で、表画面に描画するのがいいのかもしれませんね。~
なのでまずは、WM_ERASEBKGNDで何もしないようにします。~
背景ブラシがNULLになっていれば、実質、DefWindowProcは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の処理を作り、その中でバックバッファを作成することにしましょう。~
ただし、毎回バックバッファを作り直すのは効率が悪いので、クライアント領域のサイズを保持しておき、サイズが変わることがあれば、そのサイズでバックバッファを作り直すという処理にします。~
縦画面/横画面の切り替わりで、クライアント領域のサイズが変わるはずなので、描画のタイミングでサイズチェックを行えば、問題なく検知できるはずです。~
普通のWindowsプログラムだと、モニタの切り替わりをWM_DISPLAYCHANGEで捕まえたりしますが、そういう考慮は必要なさそうですね。~
縦横切り替えの検知は、サイズ変更でしか知り得ないのかな……?~
その辺りは後々調べますか……。~
バックバッファ作成のために、Todayウィンドウクラスに、以下のようなメンバを追加します。~
HDC m_hdc; // デバイスコンテキスト
HBITMAP m_hOldbmp; // ビットマップハンドル
RECT m_rect; // クライアント矩形保存用
それぞれ、表示画面と互換性のあるデバイスコンテキストを保存しておくメンバと、表示画面と互換性のあるビットマップをデバイスコンテキストに関連付けた際に、元々関連付けられていたデフォルトのビットマップが返されるので、それを後で戻すために保持しておくメンバと、サイズ変更を検知するために、作成時のクライアント矩形を覚えておくメンバになります。~
バックバッファ作成前に、GetClientRectでクライアント領域を取得し、メンバに保存してある領域とサイズが同じであれば、特に何もしません。~
サイズに変更がある場合のバックバッファ作成の流れは、解放用の関数をコールし、古いバックバッファがあれば削除した後、GetDCで表示ウィンドウのデバイスコンテキストを取得し、CreateCompatibleDCでそれと互換性のある裏画面デバイスコンテキストを作成します。~
次に、ウィンドウのデバイスコンテキストからCreateCompatibleBitmapで、表示画面と互換性のあるビットマップを作成し、SelectObjectで裏画面デバイスコンテキストに関連付けます。~
ビットマップをSelectObjectするのは、windowsx.hにSelectBitmapマクロがありますので、それを使うといいでしょう。~
作り終わったら、今回作成した領域の矩形を、メンバに保存しておきます。~
裏画面を作り終わったら、まずはこの裏画面に、透かした背景をシェル側に描いて貰う必要があります。~
このためには、TODAYDRAWWATERMARKINFOという構造体に、アイテムのウィンドウハンドルと、描画対象のデバイスコンテキスト、アイテムウィンドウの描画矩形を設定して、TODAYM_DRAWWATERMARKというメッセージを、アイテムの親ウィンドウに発行するという手順が必要になります。