VC++界面编程之--阴影窗口的实现详解

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

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

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

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

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

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

[html] view plain copy

  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,否则阴影窗口就跑到主窗口里面去了。

[cpp] view plain copy

  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是让窗口无法接收点击消息,你总不想你的窗口阴影可以被用户点击且激活吧:)

[cpp] view plain copy

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

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

[cpp] view plain copy

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

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

[cpp] view plain copy

  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+的画法,如果有童鞋觉得效果不够好,可以尝试多改改参数配置,以达到理想效果:

[cpp] view plain copy

  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);

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


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

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

[cpp] view plain copy

  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

时间: 2024-10-08 17:24:10

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

VC++界面编程之--仿Facebook透明登录窗口

1. 开发工具:VC++ DUIEngine: 该工程由DUIEngine创建,没了解过DUIE的同学,可以看前面的DUIE配置文章:点击打开链接 编译DUIE工程时,请选择"全部重新构建"构建所有的工程,以确保所有的更改都能生效.因为当你修改XML文件后,VS不会把其当做更新项,进行重新构建. 2. 制作图像文件,并拷贝至DUIE工程的skin\image文件夹下: DUIE的皮肤默认图像文件都是PNG类型的,所以尽量不要用bmp格式的,以免有些半透明的效果无法显示. 还有一点是:有

C# 网络编程之豆瓣OAuth2.0认证详解和遇到的各种问题及解决

        最近在帮人弄一个豆瓣API应用,在豆瓣的OAuth2.0认证过程中遇到了各种问题,同时自己需要一个个的尝试与解决,最终完成了豆瓣API的访问.作者这里就不再吐槽豆瓣的认证文档了,毕竟人家也不容易.但是作者发现关于豆瓣OAuth认证过程的文章非常之少,所以想详细写这样一篇文章方便后面要做同样东西的人阅读.希望文章对大家有所帮助,尤其是想做豆瓣API开发的初学者. (文章中蓝色字表示官方文档引用,红色字是可能遇到问题及注意,黑色字是作者叙述) 一.误区OAuth1.0认证过程    

DEM山体阴影原理以及算法详解

山体阴影原理以及算法详解 山体阴影基本原理: 山体阴影是假想一个光源在某个方向和某个太阳高度的模拟下,用过临近像元的计算来生成一副0-255的灰度图. 一.山体阴影的主要参数: 1.  太阳光线的入射角度:这个角度的量算起点是正北方向,按照顺时针的方向,角度的范围是0到360度,如下图所示,默认的角度是315度,西北方向,如下图所示: 2.  太阳高度角:太阳高度角也简称太阳高度.是太阳光线和当地地平面之间的夹角,范围是0-90度,默认的太阳高度是45度,如下图所示: 二.山体阴影计算方法 山体

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

目标大纲 文章转载 CSS3 经典教程系列:CSS3 盒阴影(box-shadow)详解 IE中CSS-filter滤镜小知识大全

C#网络编程基础之进程和线程详解

在C#的网络编程中,进程和线程是必备的基础知识,同时也是一个重点,所以我们要好好的掌握一下. 一:概念 首先我们要知道什么是"进程",什么是"线程",好,查一下baike. 进程:是一个具有一定独立功能的程序关于某个数据集合的一次活动.它是操作系统动态执行的基本单元, 在传统的操作系统中,进程既是基本的分配单元,也是基本的执行单元. 线程:是"进程"中某个单一顺序的控制流. 关于这两个概念,大家稍微有个印象就行了,防止以后被面试官问到. 二:进程

C#函数式编程中的标准高阶函数详解

何为高阶函数 大家可能对这个名词并不熟悉,但是这个名词所表达的事物却是我们经常使用到的.只要我们的函数的参数能够接收函数,或者函数能够返回函数,当然动态生成的也包括在内.那么我们就将这类函数叫做高阶函数.但是今天我们的标题并不是高阶函数,而是标准高阶函数,既然加上了这个标准,就意味着在函数式编程中有一套标准的函数,便于我们每次调用.而今天我们将会介绍三个标准函数,分别为Map.Filter.Fold. Map 这个函数的作用就是将列表中的每项从A类型转换到B类型,并形成一个新的类型.下面我们可以

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

CComboBox控件详解 CComboBox控件又称作组合框控件,其有三种形态可供选择,1.简单组合框(Simple)2.下拉组合框(Drop-down)3.下拉列表式组合框(Drop-down list). CComboBox控件的常用设置属性说明: type属性:里面一共有三个选项.就是其三种形式, 我们常用的是后两种形态,其区别就是Dropdown的编辑区为可编辑控件,而droplist为静态控件. Data属性:当程序初始化的时候,下拉列表将显示其属性里面的内容,内容用分号分隔.其属性

UNIX网络编程入门——TCP客户/服务器程序详解

前言 最近刚开始看APUE和UNP来学习socket套接字编程,因为网络这方面我还没接触过,要等到下学期才上计算机网络这门课,所以我就找了本教材啃了一两天,也算是入了个门. 至于APUE和UNP这两本书,书是好书,网上也说这书是给进入unix网络编程领域初学者的圣经,这个不可置否,但这个初学者,我认为指的是接受过完整计算机本科教育的研究生初学者,需要具有完整计算机系统,体系结构,网络基础知识.基础没打好就上来啃书反而会适得其反,不过对于我来说也没什么关系,因为基础课也都上得差不多了,而且如果书读

Qt界面编程之多窗口切换

1.基础知识 信号和槽 信号和槽都是函数,用来完成信号间的协同操作 2.多窗口切换实例       功能 实现登录和重新登录功能 组成 登录界面 和主窗体界面 3.源代码提供