转载:http://blog.csdn.net/rmxming/article/details/11661365

对于我们这些控件狂来说,窗口阴影也是一个必不可少的实现需求。虽说其没多大用,但对于增加窗口立体感来说,那是挺有帮助的。

我实现了一个类似于360界面的阴影效果,其可以支持正常窗口,也支持半透明窗口。

阴影窗口对于正常窗口和半透明窗口,有区别么?且让我慢慢写来:)

阴影窗口的实现原理,简单来讲:就是在主窗口创建时,创建一个子窗口,吸附于主窗口的底部。然后在子窗口上做一个带半透明阴影效果的描绘。

以下代码是阴影窗口在父窗口的创建代码,是不是很简单?

  1. LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)
  2. {
  3. m_Shadow.Create(m_hWnd);
  4. m_Shadow.SetShadowSize(8);
  5. return TRUE;
  6. }

下面是阴影窗口实现步骤:

1. 在阴影窗口创建时,只设定阴影窗口的样式为WS_VISIBLE,我们这里不能用WS_CHILD,否则阴影窗口就跑到主窗口里面去了。

  1. // Create shadow window.
  2. HWND Create(const HWND wndParent)
  3. {
  4. ATLASSERT( ::IsWindow(wndParent) );
  5. m_hParentWnd = wndParent;
  6. CRect rc(1, 1, 1, 1);
  7. return CWindowImpl<CThemedShadowWnd, CWindow, CControlWinTraits>::Create(0, rc, NULL, WS_VISIBLE, NULL);
  8. }

2. 在阴影窗口执行WM_CREATE消息时,修改其样式为WS_EX_LAYERED | WS_EX_TRANSPARENT,注意这两个样式都要要。WS_EX_TRANSPARENT是让窗口无法接收点击消息,你总不想你的窗口阴影可以被用户点击且激活吧:)

  1. SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);
  2. ModifyStyleEx(WS_EX_TOPMOST, WS_EX_NOACTIVATE);

3. 与此同时,阴影窗口注册父窗口的消息处理回调函数,此举是为了获取父窗口的移动、重绘和隐藏等重要消息。因为阴影窗口要跟随着父窗口的状态改变而改变。

  1. // Set parent window original processing.
  2. m_OriParentProc = ::GetWindowLong(m_hParentWnd, GWL_WNDPROC);
  3. ::SetWindowLong(m_hParentWnd, GWL_WNDPROC, (LONG)ParentProc);

回调函数要做的事情很简单,吸附于父窗口之下,像个小尾巴一样:

  1. // Get parent message.
  2. static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
  3. {
  4. // Find the shadow window pointer via parent window handle.
  5. ATLASSERT( m_szShadowWindows.find(hwnd) != m_szShadowWindows.end() );
  6. CThemedShadowWnd *pThis = m_szShadowWindows[hwnd];
  7. WNDPROC pDefProc        = (WNDPROC)pThis->m_OriParentProc;
  8. switch(uMsg)
  9. {
  10. case WM_ERASEBKGND:
  11. case WM_PAINT:
  12. case WM_MOVE:
  13. case WM_ACTIVATE:
  14. case WM_NCACTIVATE:
  15. {
  16. if (::IsWindowVisible(hwnd))
  17. {
  18. pThis->AdjustWindowPos();
  19. }
  20. break;
  21. }
  22. case WM_DESTROY:
  23. {
  24. // Destroy the shadow window.
  25. pThis->DestroyWindow();
  26. break;
  27. }
  28. case WM_NCDESTROY:
  29. {
  30. // Remove shadow window from map.
  31. m_szShadowWindows.erase(hwnd);
  32. break;
  33. }
  34. case WM_SHOWWINDOW:
  35. {
  36. // the window is being hidden
  37. if (!wParam)
  38. {
  39. pThis->ShowWindow(SW_HIDE);
  40. }
  41. else
  42. {
  43. pThis->ShowWindow(SW_SHOW);
  44. }
  45. break;
  46. }
  47. default:
  48. {
  49. break;
  50. }
  51. }
  52. return pDefProc(hwnd, uMsg, wParam, lParam);
  53. }

好了,窗口消息机制处理完了,就要处理阴影画法了,我这里用的是GDI+的画法,如果有童鞋觉得效果不够好,可以尝试多改改参数配置,以达到理想效果:

  1. // Create shadow brush.
  2. PathGradientBrush brShadow(m_ShadowPath.m_pPath);
  3. Color clrShadow[3] = {Color::Transparent, Color(255, 0, 0, 0), Color(255, 0, 0, 0)};
  4. int nCount = 3;
  5. REAL szPos[3] = {0.0F, 0.05F, 1.0F};
  6. brShadow.SetInterpolationColors(clrShadow, szPos, nCount);
  7. // Draw shadow.
  8. rcShadow.Width  = rcShadow.Width - m_nShadowSize - m_nBlankArea;
  9. rcShadow.Height = rcShadow.Height - m_nShadowSize - m_nBlankArea;
  10. graphics.ExcludeClip(rcShadow);
  11. graphics.FillPath(&brShadow, m_ShadowPath.m_pPath);

注意我这里排除了一部分的阴影部分,那是为透明窗口制作的,排除的效果图如下,阴影窗口只显示在矩形的右下角,而其他地方是透明的。


如果我不排除一部分阴影区域,那么透明的窗口效果将变得很难看,如下图,透明背景被阴影遮盖了,这显然不符合美学的要求。

如果你的窗口的角是椭圆的,你可能还需要增宽阴影的显示区域,那么可以用如下函数进行阴影的宽度增长:

  1. // Set blank area right position.
  2. void SetRightOffsetArea(const int nRightPos)
  3. {
  4. m_nBlankArea = nRightPos;
  5. if (nRightPos < 0)
  6. {
  7. m_nBlankArea = 1;
  8. }
  9. }

阴影窗口免费实例代码下载:http://download.csdn.net/detail/renstarone/6267677

VC++界面编程之--阴影窗口的实现详解的更多相关文章

  1. Android 之窗口小部件详解(三)  部分转载

    原文地址:http://blog.csdn.net/iefreer/article/details/4626274. (一) 应用程序窗口小部件App Widgets 应用程序窗口小部件(Widget ...

  2. Android 之窗口小部件详解--App Widget

    Android 之窗口小部件详解--App Widget  版本号 说明 作者 日期  1.0  添加App Widge介绍和示例  Sky Wang 2013/06/27        1 App ...

  3. 转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解

    目标大纲 文章转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解 IE中CSS-filter滤镜小知识大全 CSS实现跨浏览器兼容性的盒阴影效果

  4. [置顶] VC++界面编程之--使用分层窗口实现界面皮肤

    使用分层界面来实现界面皮肤的好处是:可以保证图片边缘处理不失真,且能用于异形窗口上,如一些不规则的窗口,你很难用SetWindowRgn来达到理想效果. 在很多情况下,界面的漂亮与否,取决于PS的制作 ...

  5. VC++界面编程之--使用分层窗口实现界面皮肤

    使用分层界面来实现界面皮肤的好处是:可以保证图片边缘处理不失真,且能用于异形窗口上,如一些不规则的窗口,你很难用SetWindowRgn来达到理想效果. 在很多情况下,界面的漂亮与否,取决于PS的制作 ...

  6. VC/MFC中的CComboBox控件使用详解

    CComboBox控件详解 CComboBox控件又称作组合框控件,其有三种形态可供选择,1.简单组合框(Simple)2.下拉组合框(Drop-down)3.下拉列表式组合框(Drop-down l ...

  7. VMware 虚拟化编程(14) — VDDK 的高级传输模式详解

    目录 目录 前文列表 虚拟磁盘数据的传输方式 Transport Methods Local File Access NBD and NBDSSL Transport SAN Transport Ho ...

  8. 网页打开新窗口——Window.open()详解

    转载自:http://blog.csdn.net/business122/article/details/8281142 Window.Open详解 一.window.open()支持环境:JavaS ...

  9. Java 异步编程 (5 种异步实现方式详解)

    ​ 同步操作如果遇到一个耗时的方法,需要阻塞等待,那么我们有没有办法解决呢?让它异步执行,下面我会详解异步及实现@mikechen 目录 什么是异步? 一.线程异步 二.Future异步 三.Comp ...

随机推荐

  1. 10---Net基础加强

    复习: using System; using System.Collections.Generic; using System.Linq; using System.Text; using Syst ...

  2. smarty简单介绍

    smarty简单介绍 示意图如下 简单介绍smarty.class.php类的大体内容,如下: <?php class Smarty //此类就是libs中的Smarty.class.php类 ...

  3. [转]Delphi多线程编程入门(一)

    最近Ken在比较系统地学习Delphi多线程编程方面的知识,在网络上查阅了很多资料.现在Ken将对这些资料进行整理和修改,以便收藏和分享.内容基本上是复制粘贴,拼拼凑凑,再加上一些修改而来.各个素材的 ...

  4. java中length,length(),size()的区别

    1. java中的length属性是针对数组说的,比如说你声明了一个数组,想知道这个数组的长度则用到了length这个属性.2. java中的length()方法是针对字符串String说的,如果想看 ...

  5. 160923、项目管理模式:如何去除SVN标记

    项目管理模式:如何去除SVN标记 当我们从工作空间中拷贝一个项目,发现项目特别大.那是因为当使用svn里面保留了每个版本的信息,我们可以通过这个方法来进行去除 当项目不需要SVN标志的时候,我们一般怎 ...

  6. Hadoop三种安装模式:单机模式,伪分布式,真正分布式

    Hadoop三种安装模式:单机模式,伪分布式,真正分布式 一 单机模式standalone单 机模式是Hadoop的默认模式.当首次解压Hadoop的源码包时,Hadoop无法了解硬件安装环境,便保守 ...

  7. Java生产者和消费者问题

    容器类Box.java public class Box { private int num = 0; public void put(){ if(num==10){ try { System.out ...

  8. lz: linux ls 变种 只显示大小和名称(包括目录)

    本次输入法使用: 手心输入法 for Mac 1.0版 测试环境为:Ubuntu 14.14.2 LTS updates 测试时间为:2015年5月28日,感觉死亡将至的夜晚,独自一人坐在一个角落,戴 ...

  9. oracle 自定义聚合函数(MAX_O3_8HOUR_ND) 计算最大的臭氧8小时滑动平均值

    create or replace function MAX_O3_8HOUR_ND(value NUMBER) return NUMBER parallel_enable aggregate usi ...

  10. Hibernate,JPA注解@ManyToMany_JoinTable

    可以通过@ManyToMany注解可定义的多对多关联.同时,也需要通过注解@JoinTable描述关联表和关联条件.如果是双向关联,其中一段必须定义为owner,另一端必须定义为inverse(在对关 ...