1. 程式人生 > >如何讓視窗控制元件半透明

如何讓視窗控制元件半透明

在網上關於視窗視覺效果,有2個問題被問得最多:
第一個是如何讓視窗邊框有陰影效果?
第二個是如何讓視窗控制元件有半透明效果?

對於第一個問題,我們的答案是用雙層視窗模擬或是用Layered Window。
在XP下可以直接在註冊視窗類時用CS_DROPSHADOW風格,系統就會自動讓你的視窗附加上陰影效果,實際上系統也是通過雙層視窗來實現的;當然我們也可以用自己的視窗來模擬陰影效果,只要讓陰影視窗永遠跟隨我們的目標視窗就可以了。
如果用Layered Window, 我們只要一個視窗,通過讓視窗支援Alpha通道,最後UpdateLayeredWindow, 即可實現陰影效果。

對於第二個問題,我們通常的答案是用雙層窗體或是DirectUI。
因為Windows繪畫是以DC為單位,而主視窗和內部控制元件是居於不同的DC, 所以他們不能半透明融合在一起。
另外只有Pop up的窗口才能支援Layered Window,所以只有Pop up的窗口才能實現半透明效果,所以我們通常用雙層視窗來模擬控制元件的半透明,也就是說視窗上面的控制元件其實是通過一個Pop up視窗模擬出來的。所以用這種方式實現控制元件的半透明效果,效能比較差,也只能實現一些簡單的介面。
還有一種控制元件半透明的方式是用DirectUI,所有的視窗控制元件都通過在主視窗上繪畫模擬出來,實現半透明效果自然也很容易了。

所以既要實現視窗的陰影效果,又要讓內部控制元件半透明,最終極的方式還是用WS_EX_LAYERED風格的DirectUI視窗。

其實另外還有一種既不用DirectUI,也不用雙層視窗,也能實現控制元件半透明的方法。
該方法的關鍵是控制元件在Paint自己時,首先向主視窗詢問,獲取主視窗上控制元件所在區域的背景圖,然後控制元件先將此背景畫到自己的DC上,然後在再畫自己,這樣可以讓控制元件看起來像是直接畫在主視窗上一樣。
當然該方法也只能針對一些簡單的UI,如果子視窗層次很多,或是控制元件個數很多,都會有效能影響。

核心程式碼如下:
HBRUSH AtlGetBackgroundBrush(HWND hWnd, HWND hwndParent)
{
   CWindow wnd = hWnd;
   CWindow wndParent = hwndParent;
   CClientDC dcParent = wndParent;
   CRect rcParent;
   wndParent.GetWindowRect(&rcParent);
   CDC dcCompat1;
   dcCompat1.CreateCompatibleDC(dcParent);
   CBitmap bmpCompat1;
   bmpCompat1.CreateCompatibleBitmap(dcParent, rcParent.Width(), rcParent.Height());
   HBITMAP hOldBmp1 = dcCompat1.SelectBitmap(bmpCompat1);
   wndParent.SendMessage(WM_PRINTCLIENT, (WPARAM) (HDC) dcCompat1, (LPARAM)(PRF_ERASEBKGND | PRF_CLIENT | PRF_NONCLIENT));
   CRect rcWin;
   wnd.GetWindowRect(&rcWin);
   CDC dcCompat2;
   dcCompat2.CreateCompatibleDC();
   CBitmap bmpCompat2;
   bmpCompat2.CreateCompatibleBitmap(dcCompat1, rcWin.Width(), rcWin.Height());
   HBITMAP hOldBmp2 = dcCompat2.SelectBitmap(bmpCompat2);
   CRect rcSnap = rcWin;
   ::MapWindowPoints(NULL, wndParent, (LPPOINT) (LPRECT) &rcSnap, 2);
   dcCompat2.BitBlt(0, 0, rcWin.Width(), rcWin.Height(), dcCompat1, rcSnap.left, rcSnap.top, SRCCOPY);
   HBRUSH hBrush = ::CreatePatternBrush(bmpCompat2);
   dcCompat1.SelectBitmap(hOldBmp1);
   dcCompat2.SelectBitmap(hOldBmp2);
   return
 hBrush;
}
下面是一個簡單的Demo:


Demo原始碼: 注:Demo上的文字因為是直接用GDI畫的,所以沒有支援Alpha通道 posted on 2012-08-23 00:38 Richard Wei 閱讀(5461) 評論(4)  編輯 收藏 引用 所屬分類: windows desktop