窗口玻璃特效,半透明窗口,使用DWM實現Aero Glass效果

轉自:http://blog.csdn.net/ntwilford/article/details/5656633算法

從Windows Vista開始,Aero Glass效果被應用在了Home Premium以上的系統中(Home Basic不具備該效果)。這種效果是由DWM(Desktop Window Manager)來控制的。對於通常的程序,缺省將在窗口邊框應用這種效果。但若是咱們想要更多的控制,好比讓客戶區的一部分也呈現這種效果,那也很是的簡單。不須要咱們在程序裏作任何複雜的算法,咱們只須要調API,交給DWM去作就能夠了。app

1、Composition(窗口合成) and Non-client Rendering(非客戶區渲染)

       非客戶區一般包括窗口標題欄和窗口邊框。缺省狀態下,非客戶區會被渲染成毛玻璃效果,這也稱爲Compostion。有幾個函數能夠控制系統和當前窗口的渲染方式。同時也有Windows消息用於接受渲染模式的改變。函數

       1.檢測系統是否開啓Aero Glass。使用 函數 DwmIsCompositionEnabled 檢測系統當前是否開啓了Aero Glass特效。它接受一個BOOL參數,並將當前狀態存儲到其中。函數原型:HRESULT DwmIsCompositionEnabled(BOOL *pfEnabled );oop

       2.開啓/關閉Aero Glass。使用函數DwmEnableComposition 開啓或關閉系統Aero Glass效果,傳入DWM_EC_ENABLECOMPOSITION 開啓,傳入DWM_EC_DISABLECOMPOSITION 關閉。post

       3.開啓/關閉當前窗口的非客戶區渲染。函數DwmSetWindowAttribute 用於設置窗口屬性,屬性DWMWA_NCRENDERING_POLICY 控制當前窗口是否使用非客戶區渲染。DWMNCRP_ENABLED 開啓,DWMNCRP_DISABLED 關閉。當系統的Aero Glass關閉時,設置無效。與之對應,使用函數DwmGetWindowAttribute 能夠檢測當前窗口屬性。字體

       4.響應系統Aero Glass的開啓或關閉。當Aero Glass被開啓或關閉時,Windows會發送消息WM_DWMCOMPOSITIONCHANGED , 使用 函數 DwmIsCompositionEnabled 檢測狀態。動畫

       5.響應窗口非客戶區渲染的開啓或關閉。當前窗口的非客戶區渲染開啓或關閉時,Windows會發送消息WM_DWMNCRENDERINGCHANGED ,wParam 指示當前狀態。spa

2、Transition(窗口動畫) and ColorizationColor(主題顏色)

       Transition控制是否以動畫方式顯示窗口的最小化和還原。經過使用函數DwmSetWindowAttribute ,設置屬性DWMWA_TRANSITIONS_FORCEDISABLED ,開啓或關閉窗口動畫。該設置只對當前窗口有效。.net

       當用戶經過控制面板修改主題顏色時,Windows將發送消息WM_DWMCOLORIZATIONCOLORCHANGED ,程序中經過函數DwmGetColorizationColor 取得當前主題顏色,以及是否透明。經過響應顏色的變動,可讓程序的顏色風格隨主題風格而變化。blog

3、開啓客戶區域Aero Glass效果

       函數DwmEnableBlurBehindWindow 開啓客戶區的Aero Glass效果,第一個參數爲窗口句柄,第二個參數爲一個DWM_BLURBEHIND 結構。其中fEnable 設置是否開啓客戶區Glass效果。hRgnBlur 設置Glass效果的區域,該項設置爲NULL將使整個客戶區呈現Glass效果,設置爲一個正確的區域後,該區域將呈現Glass效果, 而區域之外爲徹底透明。要呈現透明效果須要客戶區原始的顏色爲黑色,能夠在WM_PAINT 消息中繪製客戶區,下面的代碼使用GDI+,在Aero Glass開啓時將整個窗口繪製爲黑色,Aero Glass關閉時繪製爲灰色:

 

[cpp]  view plain copy
  1. case WM_PAINT:  
  2.     {  
  3.         PAINTSTRUCT ps;  
  4.         HDC hDC = BeginPaint(hWnd, &ps);  
  5.         //不要直接使用窗口句柄建立Graphics,會致使閃爍  
  6.         Graphics graph(hDC);  
  7.         //清除客戶區域  
  8.         RECT rcClient;  
  9.         GetClientRect(hWnd, &rcClient);  
  10.         BOOL bCompEnabled;  
  11.         DwmIsCompositionEnabled(&bCompEnabled);  
  12.         SolidBrush br(bCompEnabled? Color::Black : Color::DarkGray);  
  13.         graph.FillRectangle(&br, Rect(rcClient.left, rcClient.top,   
  14.             rcClient.right, rcClient.bottom));  
  15.         EndPaint(hWnd, &ps);  
  16.     }  
  17.     break;  

 

        GDI+的初始化和關閉仍然是必須的:

 

[cpp]  view plain copy
  1. //初始化GDI+  
  2. ULONG_PTR token;  
  3. GdiplusStartupInput input;  
  4. GdiplusStartup(&token, &input, NULL);  
  5. //*********************************  
  6. //關閉GDI+  
  7. GdiplusShutdown(token);  

 

       下面代碼將整個客戶區設置爲Glass效果:

 

[cpp]  view plain copy
  1. DWM_BLURBEHIND bb = {0};  
  2. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;  
  3. bb.fEnable = true;  
  4. bb.hRgnBlur = NULL;  
  5. DwmEnableBlurBehindWindow(hWnd, &bb);  

 

      下面代碼將客戶區中心一個橢圓的區域設置爲Glass效果:

 

[cpp]  view plain copy
  1. RECT rect;  
  2. GetWindowRect(hWnd, &rect);  
  3. int width = 300, height = 200;  
  4. //居中橢圓形  
  5. HRGN hRgn = CreateEllipticRgn((rect.right - rect.left)/2 - width/2,   
  6.     (rect.bottom - rect.top)/2 - height/2, (rect.right - rect.left)/2 + width/2,   
  7.     (rect.bottom - rect.top)/2 + height/2);  
  8. DWM_BLURBEHIND bb = {0};  
  9. bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;  
  10. bb.fEnable = true;  
  11. bb.hRgnBlur = hRgn;  
  12. DwmEnableBlurBehindWindow(hWnd, &bb);  

 

4、窗口邊框向客戶區擴展

      上面的方式中,非客戶區和客戶區之間仍然有界限。如何增大Glass效果的範圍,而且消除界限呢?那就是使窗口邊框向客戶區擴展,利用函數DwmExtendFrameIntoClientArea 實現。函數接受一個窗口句柄和一個MARGINS 類型的參數。MARGINS指定了在上下左右4個方向上擴展的範圍。若是4個值均爲-1,則擴展到整個客戶區。

 

[cpp]  view plain copy
  1. MARGINS margins = {50, 50, 50, 50};  
  2. DwmExtendFrameIntoClientArea(hWnd, &margins);  

 

 

[cpp]  view plain copy
  1. MARGINS margins2 = {-1};    //將擴展到整個客戶區  
  2. DwmExtendFrameIntoClientArea(hWnd, &margins2);  

 

5、在窗口上繪製圖形

      PNG圖片帶有alpha通道,能夠與Aero Glass很好的配合。利用GDI+顯示PNG圖片很是方便,下面的代碼將一張PNG圖片加載到內存中:

 

[cpp]  view plain copy
  1. Bitmap bmp  = Bitmap::FromFile(L"Ferrari.png"false);  

 

      在WM_PAINT消息處理中,將整個客戶區繪製爲黑色之後,利用GDI+將圖片繪製到窗口客戶區:

 

[cpp]  view plain copy
  1. //繪製圖形  
  2. int width = bmp->GetWidth();  
  3. int height = bmp->GetHeight();  
  4. Rect rc(30, 30, width, height);  
  5. graph.DrawImage(bmp, rc, 0, 0, width, height, UnitPixel);  

 

6、文本的繪製

      當窗口大範圍的透明以後,窗口上的文字的閱讀成了一個問題。Windows的解決辦法是爲文字加上發光效果(Glowing),標題欄的文本使用的就是這種方式。咱們在本身的程序中可使用DrawThemeTextEx 函數來繪製發光的文字。該函數的原型定義以下:

 

[cpp]  view plain copy
  1. HRESULT DrawThemeTextEx(          HTHEME hTheme,  
  2.     HDC hdc,  
  3.     int iPartId,  
  4.     int iStateId,  
  5.     LPCWSTR pszText,  
  6.     int iCharCount,  
  7.     DWORD dwFlags,  
  8.     LPRECT pRect,  
  9.     const DTTOPTS *pOptions  
  10. );  

 

      hTheme是一個主題句柄,可使用OpenThemeData 得到, OpenThemeData 函數接受一個窗口句柄,和主題類的名稱。iPartId和iStateId分別表明主題類中的Part和State,全部可用的主題類、Part和state在SDK的幫助文檔中能夠查看到。pszText是要繪製的文本。iCharCount爲文字個數,-1表明繪製所有文本。dwFlags指定文本格式。pRect爲文本繪製區域。pOptions中能夠設定文本的發光、陰影等效果。HDC是一個設備上下文句柄,爲了實現相似於標題欄中文本的發光效果,這裏不能使用由BeginPaint 獲得的句柄,而是要使用CreateCompatibleDC 建立一個內存中的句柄,而且要建立一張位圖,經過內存句柄將文本繪製到位圖上。而後再將位圖轉移到窗口上。下面的函數封裝了繪製發光文本的過程:

 

[cpp]  view plain copy
  1. //繪製發光文字  
  2. void DrawGlowingText(HDC hDC, LPWSTR szText, RECT &rcArea,   
  3.     DWORD dwTextFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE, int iGlowSize = 10)  
  4. {  
  5.     //獲取主題句柄  
  6.     HTHEME hThm = OpenThemeData(GetDesktopWindow(), L"TextStyle");  
  7.     //建立DIB  
  8.     HDC hMemDC = CreateCompatibleDC(hDC);  
  9.     BITMAPINFO bmpinfo = {0};  
  10.     bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader);  
  11.     bmpinfo.bmiHeader.biBitCount = 32;  
  12.     bmpinfo.bmiHeader.biCompression = BI_RGB;  
  13.     bmpinfo.bmiHeader.biPlanes = 1;  
  14.     bmpinfo.bmiHeader.biWidth = rcArea.right - rcArea.left;  
  15.     bmpinfo.bmiHeader.biHeight = -(rcArea.bottom - rcArea.top);  
  16.     HBITMAP hBmp = CreateDIBSection(hMemDC, &bmpinfo, DIB_RGB_COLORS, 0, NULL, 0);  
  17.     if (hBmp == NULL) return;  
  18.     HGDIOBJ hBmpOld = SelectObject(hMemDC, hBmp);  
  19.     //繪製選項  
  20.     DTTOPTS dttopts = {0};  
  21.     dttopts.dwSize = sizeof(DTTOPTS);  
  22.     dttopts.dwFlags = DTT_GLOWSIZE | DTT_COMPOSITED;  
  23.     dttopts.iGlowSize = iGlowSize;  //發光的範圍大小  
  24.     //繪製文本  
  25.     RECT rc = {0, 0, rcArea.right - rcArea.left, rcArea.bottom - rcArea.top};  
  26.     HRESULT hr = DrawThemeTextEx(hThm, hMemDC, TEXT_LABEL, 0, szText, -1, dwTextFlags , &rc, &dttopts);  
  27.     if(FAILED(hr)) return;  
  28.     BitBlt(hDC, rcArea.left, rcArea.top, rcArea.right - rcArea.left,   
  29.         rcArea.bottom - rcArea.top, hMemDC, 0, 0, SRCCOPY | CAPTUREBLT);  
  30.     //Clear  
  31.     SelectObject(hMemDC, hBmpOld);  
  32.     DeleteObject(hBmp);  
  33.     DeleteDC(hMemDC);  
  34.     CloseThemeData(hThm);  
  35. }  

 

      在繪製了圖形後,加入下面代碼繪製一段文本:

 

[cpp]  view plain copy
  1. //繪製文本  
  2. RECT rcText = {10, 10, 300, 40};  
  3. DrawGlowingText(hDC, L"  一點點中文 and some english", rcText);  

 

     由於字體發光的緣故,在文本左側留下一個空格看起來會舒服一些。效果以下:

7、縮略圖關聯

       DWM API中還有一個功能,即縮略圖關聯。它容許咱們將一個窗口的縮略圖顯示到本身窗口的客戶區。縮略圖不一樣於截圖,它是實時更新的。下面的代碼將在窗口客戶區顯示QQ影音播放器的縮略圖:

 

[cpp]  view plain copy
  1. HRESULT hr = S_OK;  
  2. HTHUMBNAIL thumbnail = NULL;  
  3. HWND hWndSrc = FindWindow(_T("QQPlayer Window"), NULL);  
  4. hr = DwmRegisterThumbnail(hWnd, hWndSrc, &thumbnail);  
  5. if (SUCCEEDED(hr))  
  6. {  
  7.     RECT rc;  
  8.     GetClientRect(hWnd, &rc);  
  9.     DWM_THUMBNAIL_PROPERTIES dskThumbProps;  
  10.     dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE | DWM_TNP_OPACITY ;  
  11.     dskThumbProps.fVisible = TRUE;  
  12.     dskThumbProps.opacity = 200;  
  13.     dskThumbProps.rcDestination = rc;  
  14.     hr = DwmUpdateThumbnailProperties(thumbnail,&dskThumbProps);  
  15. }  

 

       首先經過窗口標題查找到源窗口句柄,而後使用DwmRegisterThumbnail 註冊縮略圖關聯,註冊成功後,經過DwmUpdateThumbnailProperties 更新縮略圖屬性,其中設定了是否可視、透明度以及目標繪製區域。獲得下面的效果:

 

 

項目圖,轉.rar

相關文章
相關標籤/搜索