窗口玻璃特效,半透明窗口,使用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去做就可以了。
一、Composition(窗口合成) and Non-client Rendering(非客户区渲染)
非客户区通常包括窗口标题栏和窗口边框。缺省状态下,非客户区会被渲染成毛玻璃效果,这也称为Compostion。有几个函数可以控制系统和当前窗口的渲染方式。同时也有Windows消息用于接受渲染模式的改变。
1.检测系统是否开启Aero Glass。使用 函数 DwmIsCompositionEnabled 检测系统当前是否开启了Aero Glass特效。它接受一个BOOL参数,并将当前状态存储到其中。函数原型:HRESULT DwmIsCompositionEnabled(BOOL *pfEnabled );
2.开启/关闭Aero Glass。使用函数DwmEnableComposition 开启或关闭系统Aero Glass效果,传入DWM_EC_ENABLECOMPOSITION 开启,传入DWM_EC_DISABLECOMPOSITION 关闭。
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 指示当前状态。
二、Transition(窗口动画) and ColorizationColor(主题颜色)
Transition控制是否以动画方式显示窗口的最小化和还原。通过使用函数DwmSetWindowAttribute ,设置属性DWMWA_TRANSITIONS_FORCEDISABLED ,开启或关闭窗口动画。该设置只对当前窗口有效。
当用户通过控制面板修改主题颜色时,Windows将发送消息WM_DWMCOLORIZATIONCOLORCHANGED ,程序中通过函数DwmGetColorizationColor 取得当前主题颜色,以及是否透明。通过响应颜色的变更,可以让程序的颜色风格随主题风格而变化。
三、开启客户区域Aero Glass效果
函数DwmEnableBlurBehindWindow 开启客户区的Aero Glass效果,第一个参数为窗口句柄,第二个参数为一个DWM_BLURBEHIND 结构。其中fEnable 设置是否开启客户区Glass效果。hRgnBlur 设置Glass效果的区域,该项设置为NULL将使整个客户区呈现Glass效果,设置为一个正确的区域后,该区域将呈现Glass效果, 而区域以外为完全透明。要呈现透明效果需要客户区原始的颜色为黑色,可以在WM_PAINT 消息中绘制客户区,下面的代码使用GDI+,在Aero Glass开启时将整个窗口绘制为黑色,Aero Glass关闭时绘制为灰色:
- case WM_PAINT:
- {
- PAINTSTRUCT ps;
- HDC hDC = BeginPaint(hWnd, &ps);
- //不要直接使用窗口句柄创建Graphics,会导致闪烁
- Graphics graph(hDC);
- //清除客户区域
- RECT rcClient;
- GetClientRect(hWnd, &rcClient);
- BOOL bCompEnabled;
- DwmIsCompositionEnabled(&bCompEnabled);
- SolidBrush br(bCompEnabled? Color::Black : Color::DarkGray);
- graph.FillRectangle(&br, Rect(rcClient.left, rcClient.top,
- rcClient.right, rcClient.bottom));
- EndPaint(hWnd, &ps);
- }
- break;
GDI+的初始化和关闭仍然是必须的:
- //初始化GDI+
- ULONG_PTR token;
- GdiplusStartupInput input;
- GdiplusStartup(&token, &input, NULL);
- //*********************************
- //关闭GDI+
- GdiplusShutdown(token);
下面代码将整个客户区设置为Glass效果:
- DWM_BLURBEHIND bb = {0};
- bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- bb.fEnable = true;
- bb.hRgnBlur = NULL;
- DwmEnableBlurBehindWindow(hWnd, &bb);
下面代码将客户区中心一个椭圆的区域设置为Glass效果:
- RECT rect;
- GetWindowRect(hWnd, &rect);
- int width = 300, height = 200;
- //居中椭圆形
- HRGN hRgn = CreateEllipticRgn((rect.right - rect.left)/2 - width/2,
- (rect.bottom - rect.top)/2 - height/2, (rect.right - rect.left)/2 + width/2,
- (rect.bottom - rect.top)/2 + height/2);
- DWM_BLURBEHIND bb = {0};
- bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
- bb.fEnable = true;
- bb.hRgnBlur = hRgn;
- DwmEnableBlurBehindWindow(hWnd, &bb);
四、窗口边框向客户区扩展
上面的方式中,非客户区和客户区之间仍然有界限。如何增大Glass效果的范围,并且消除界限呢?那就是使窗口边框向客户区扩展,利用函数DwmExtendFrameIntoClientArea 实现。函数接受一个窗口句柄和一个MARGINS 类型的参数。MARGINS指定了在上下左右4个方向上扩展的范围。如果4个值均为-1,则扩展到整个客户区。
- MARGINS margins = {50, 50, 50, 50};
- DwmExtendFrameIntoClientArea(hWnd, &margins);
- MARGINS margins2 = {-1}; //将扩展到整个客户区
- DwmExtendFrameIntoClientArea(hWnd, &margins2);
五、在窗口上绘制图形
PNG图片带有alpha通道,可以与Aero Glass很好的配合。利用GDI+显示PNG图片非常方便,下面的代码将一张PNG图片加载到内存中:
- Bitmap bmp = Bitmap::FromFile(L"Ferrari.png", false);
在WM_PAINT消息处理中,将整个客户区绘制为黑色以后,利用GDI+将图片绘制到窗口客户区:
- //绘制图形
- int width = bmp->GetWidth();
- int height = bmp->GetHeight();
- Rect rc(30, 30, width, height);
- graph.DrawImage(bmp, rc, 0, 0, width, height, UnitPixel);
六、文本的绘制
当窗口大范围的透明之后,窗口上的文字的阅读成了一个问题。Windows的解决办法是为文字加上发光效果(Glowing),标题栏的文本使用的就是这种方式。我们在自己的程序中可以使用DrawThemeTextEx 函数来绘制发光的文字。该函数的原型定义如下:
- HRESULT DrawThemeTextEx( HTHEME hTheme,
- HDC hdc,
- int iPartId,
- int iStateId,
- LPCWSTR pszText,
- int iCharCount,
- DWORD dwFlags,
- LPRECT pRect,
- const DTTOPTS *pOptions
- );
hTheme是一个主题句柄,可以使用OpenThemeData 获得, OpenThemeData 函数接受一个窗口句柄,和主题类的名称。iPartId和iStateId分别代表主题类中的Part和State,所有可用的主题类、Part和state在SDK的帮助文档中可以查看到。pszText是要绘制的文本。iCharCount为文字个数,-1代表绘制全部文本。dwFlags指定文本格式。pRect为文本绘制区域。pOptions中可以设定文本的发光、阴影等效果。HDC是一个设备上下文句柄,为了实现类似于标题栏中文本的发光效果,这里不能使用由BeginPaint 得到的句柄,而是要使用CreateCompatibleDC 创建一个内存中的句柄,并且要创建一张位图,通过内存句柄将文本绘制到位图上。然后再将位图转移到窗口上。下面的函数封装了绘制发光文本的过程:
- //绘制发光文字
- void DrawGlowingText(HDC hDC, LPWSTR szText, RECT &rcArea,
- DWORD dwTextFlags = DT_LEFT | DT_VCENTER | DT_SINGLELINE, int iGlowSize = 10)
- {
- //获取主题句柄
- HTHEME hThm = OpenThemeData(GetDesktopWindow(), L"TextStyle");
- //创建DIB
- HDC hMemDC = CreateCompatibleDC(hDC);
- BITMAPINFO bmpinfo = {0};
- bmpinfo.bmiHeader.biSize = sizeof(bmpinfo.bmiHeader);
- bmpinfo.bmiHeader.biBitCount = 32;
- bmpinfo.bmiHeader.biCompression = BI_RGB;
- bmpinfo.bmiHeader.biPlanes = 1;
- bmpinfo.bmiHeader.biWidth = rcArea.right - rcArea.left;
- bmpinfo.bmiHeader.biHeight = -(rcArea.bottom - rcArea.top);
- HBITMAP hBmp = CreateDIBSection(hMemDC, &bmpinfo, DIB_RGB_COLORS, 0, NULL, 0);
- if (hBmp == NULL) return;
- HGDIOBJ hBmpOld = SelectObject(hMemDC, hBmp);
- //绘制选项
- DTTOPTS dttopts = {0};
- dttopts.dwSize = sizeof(DTTOPTS);
- dttopts.dwFlags = DTT_GLOWSIZE | DTT_COMPOSITED;
- dttopts.iGlowSize = iGlowSize; //发光的范围大小
- //绘制文本
- RECT rc = {0, 0, rcArea.right - rcArea.left, rcArea.bottom - rcArea.top};
- HRESULT hr = DrawThemeTextEx(hThm, hMemDC, TEXT_LABEL, 0, szText, -1, dwTextFlags , &rc, &dttopts);
- if(FAILED(hr)) return;
- BitBlt(hDC, rcArea.left, rcArea.top, rcArea.right - rcArea.left,
- rcArea.bottom - rcArea.top, hMemDC, 0, 0, SRCCOPY | CAPTUREBLT);
- //Clear
- SelectObject(hMemDC, hBmpOld);
- DeleteObject(hBmp);
- DeleteDC(hMemDC);
- CloseThemeData(hThm);
- }
在绘制了图形后,加入下面代码绘制一段文本:
- //绘制文本
- RECT rcText = {10, 10, 300, 40};
- DrawGlowingText(hDC, L" 一点点中文 and some english", rcText);
因为字体发光的缘故,在文本左侧留下一个空格看起来会舒服一些。效果如下:
七、缩略图关联
DWM API中还有一个功能,即缩略图关联。它允许我们将一个窗口的缩略图显示到自己窗口的客户区。缩略图不同于截图,它是实时更新的。下面的代码将在窗口客户区显示QQ影音播放器的缩略图:
- HRESULT hr = S_OK;
- HTHUMBNAIL thumbnail = NULL;
- HWND hWndSrc = FindWindow(_T("QQPlayer Window"), NULL);
- hr = DwmRegisterThumbnail(hWnd, hWndSrc, &thumbnail);
- if (SUCCEEDED(hr))
- {
- RECT rc;
- GetClientRect(hWnd, &rc);
- DWM_THUMBNAIL_PROPERTIES dskThumbProps;
- dskThumbProps.dwFlags = DWM_TNP_RECTDESTINATION | DWM_TNP_VISIBLE | DWM_TNP_OPACITY ;
- dskThumbProps.fVisible = TRUE;
- dskThumbProps.opacity = 200;
- dskThumbProps.rcDestination = rc;
- hr = DwmUpdateThumbnailProperties(thumbnail,&dskThumbProps);
- }
首先通过窗口标题查找到源窗口句柄,然后使用DwmRegisterThumbnail 注册缩略图关联,注册成功后,通过DwmUpdateThumbnailProperties 更新缩略图属性,其中设定了是否可视、透明度以及目标绘制区域。得到下面的效果:
项目图,转.rar
窗口玻璃特效,半透明窗口,使用DWM实现Aero Glass效果的更多相关文章
- 【转】MFC 迅雷七窗体特效,使用DWM实现Aero Glass效果
从Windows Vista开始,Aero Glass效果被应用在了Home Premium以上的系统中(Home Basic不具有该效果).这种效果是由DWM(Desktop Window Mana ...
- C# winform窗口打开特效及窗口位置居中
在启动一个程序时,我们希望窗口显示的位置处于屏幕的正中心,可以如下设置: MainForm mainForm = new MainForm(); mainForm.StartPosition = ...
- Windows 7 扩展玻璃效果(Aero Glass)
转自:http://www.cnblogs.com/gnielee/archive/2010/10/04/windows7-extend-aero-glass.html Windows 7 操作系统默 ...
- JS弹出模态窗口下拉列表特效
效果体验:http://hovertree.com/texiao/js/20/ 或者扫描二维码在手机体验: 点击选择城市后,在弹出的层中的输入框,输入英文字母 h,会有HoverTree和Hewenq ...
- 在SOUI中非半透明窗口如何实现圆角窗口?
如果SOUI的宿主窗口没有包含子窗口,直接使用窗口的半透明属性:translucent=1就可以解决了,整个窗口形状完全由背景图决定,可以实现完美的圆角. 然后窗口半透明时,窗口中的子窗口(非SWin ...
- 在C#里实现各种窗口切换特效,多达13种特效
原文:http://www.cnblogs.com/clayui/archive/2011/06/28/2092126.html 预览: 下载 这次clayui给大家带来了比较实用的东西,因为时间 ...
- 如何让窗口控件半透明(控件在Paint自己时,首先向主窗口询问,获取主窗口上控件所在区域的背景图)
在网上关于窗口视觉效果,有2个问题被问得最多:第一个是如何让窗口边框有阴影效果?第二个是如何让窗口控件有半透明效果? 对于第一个问题,我们的答案是用双层窗口模拟或是用Layered Window.在X ...
- 利用Javascript制作网页特效(窗口特效)
全屏显示窗口 利用fullscreen=yes可以制作全屏显示窗口. ①:在body标签内输入以下代码: <div align="center"> <input ...
- jquery 获取父窗口的元素 父窗口 子窗口
一.获取页面元素 取父窗口的元素方法:$(selector, window.parent.document); 那么你取父窗口的父窗口的元素就可以用:$(selector, window.parent ...
随机推荐
- Java学习笔记之Java 继承中的构造方法
参考
- 【WIN7】windows\system32 下的几乎所有文件的简单说明【1】
1: aclui.dll .....Security Descriptor Editor,没有它,注册表编缉器会无法运行 2: ACTIVEDS.DLL .....(ADs 路由层 DLL). 没有它 ...
- Linux系统crontab定时调度Python脚本
Linux系统crontab定时调度Python脚本 一.Python脚本随Linux开机自动运行 #Python脚本:/home/edgar/auto.py #用root权限编辑以下文件:/etc/ ...
- 安装专业版的linux的方法 图解安装专业版的linux
按装一个linux系统其实很简单,不再像以前那样光光盘就好些个,一不小心还又可能装错,实在也是一个大问题.现在好了基本上都是简单安装+网络升级先安装主要的后面如果需要什么在装什么?大大简化了流程.不行 ...
- hadoop入门小知识点
注意各个主机之间的通信 文件的复制 scp指令 scp /etc/profile acm03:/etc 所有历史版本: archive.apache.org hdfs://acm01:9000 ...
- 介绍几个C#正则表达式工具
这里将为大家推荐介绍几个C#正则表达式工具,这些小工具能帮助大家在.NET开发过程中起到事半功倍的效果,希望大家喜欢. 推荐三个C#正则表达式工具,理由如下 第一个C#正则表达式工具,REGEX 这个 ...
- redhat6.4 数据包无法到达
由于redhat在初始化的时候,防火墙设置为icmp-host-prohibited,导致数据包无法到达. 具体iptables(所在目录/etc/sysconfig)如下: # Firewall c ...
- JNI_Z_05_方法的操作(没有String类型的参数)
1.步骤: (1).获取 jclass (2).获取 method的id (3).调用 method ZC: 貌似 JNI里面 操作 类的方法,完全是 无视 访问权限的... 然而 static的方法 ...
- KNN 算法,以及与Kmeans的简单对比
KNN与Kmeans感觉没啥联系,但是名字挺像的,就拿来一起总结一下吧. 初学者的总结. KNN是监督学习,Kmeans是无监督学习. KNN用于分类,Kmeans用于聚类. 先说KNN: 对于KNN ...
- 没有服务器,关于angular路由访问静态页面chrome报错的问题
这个找不到html,报错因为没有xhr,但是在火狐下没有问题的. 比如说ajax,直接写路径的话,我们的chrome也是不支持的,火狐可以的.