窗口玻璃特效,半透明窗口,使用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

相关文章
相关标签/搜索