OrangeMaker_logo
memo アイコン SDK-MFC 備忘録

Windows SDKやMFCに関するメモです。
(記載内容について正しいことを保証するものではありません。MSDN等で確認してください)

エアロで透けないボタン

2009/11/15 作成
2009/11/21 サンプル画像追加

エアロ化したウィンドウに、標準のコンポーネントを設置すると黒で描画する部分が透けてしまいます。これは、標準コンポーネントの描画がgdiで行われておりアルファチャネルが書かれていないため黒で描画する部分が透けてしまいます。(.netではGdi+で描画させるオプションがあるようです。)

これを透けないようにするには、ボタンの文字描画部分のアルファチャネルを書き込んでやればよい、

方法は、
1)ボタンクラスを継承クラスを作成する。
2)OnPaint()をオーバライドして、先に標準コンポーネントに描画してもらってからアルファチャネルを書き込む。

継承クラスの配置の仕方は静的な置き換えでもよいし、サブクラス化でも構いませんがDWMのComositの状態で切り替えを考えるとサブクラス化のほうか使いやすいかもしれません。

OnPaint()ハンドラ:
 HDC targetDC = this->GetDC()->m_hDC;
 HDC bufferedDC = NULL;
 RECT rect;
 GetClientRect(&rect);
 HPAINTBUFFER pb = BeginBufferedPaint(targetDC, &rect, 
     BPBF_TOPDOWNDIB, 0,bufferedDC);
	
 HRESULT hr = S_OK;
 if (0 == pb){
     //Error
 }
 else{
     //標準ボタンに書いてもらう
     SendMessage(WM_PRINTCLIENT, 
         reinterpret_cast<WPARAM>(bufferedDC), PRF_CLIENT);
     //ちょっと内側の矩形を作成
     RECT rr;
     rr.left = rect.left + 3;
     rr.right = rect.right -3;
     rr.top = rect.top + 3;
     rr.bottom = rect.bottom -3;
     //Alpha値を書き込む
     hr = BufferedPaintSetAlpha(pb, &rr, 255);
     if (hr != S_OK){
         //error
     }
     hr = EndBufferedPaint(pb, TRUE);
     if (hr != S_OK){
         //error
     }
 }
		

アルファチャネルを書き込む矩形は、ボタン矩形のちょっと内側にしています。ここはちょっと手抜きで正しくはフォントと文字列を読み込んで、文字描画されている矩形を計算する方が正しいと思いますが、フォントを固定していれば実質これでもよいと判断しています。ここでボタン矩形いっぱいにアルファチャネルを書き込むとボタンの4隅のラウンド部分(丸みの部分)が黒く描画されてしまいます。


Aeroなボタン (Aeroで透けないボタン)