• 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.   
    6.     return TRUE;  
    7. }  

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

    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.   
    9.     switch(uMsg)  
    10.     {  
    11.     case WM_ERASEBKGND:  
    12.     case WM_PAINT:  
    13.     case WM_MOVE:  
    14.     case WM_ACTIVATE:  
    15.     case WM_NCACTIVATE:  
    16.         {  
    17.             if (::IsWindowVisible(hwnd))   
    18.             {   
    19.                 pThis->AdjustWindowPos();   
    20.             }  
    21.             break;  
    22.         }  
    23.     case WM_DESTROY:  
    24.         {  
    25.             // Destroy the shadow window.  
    26.             pThis->DestroyWindow();    
    27.             break;  
    28.         }  
    29.     case WM_NCDESTROY:  
    30.         {  
    31.             // Remove shadow window from map.  
    32.             m_szShadowWindows.erase(hwnd);    
    33.             break;  
    34.         }  
    35.     case WM_SHOWWINDOW:  
    36.         {  
    37.             // the window is being hidden  
    38.             if (!wParam)      
    39.             {  
    40.                 pThis->ShowWindow(SW_HIDE);  
    41.             }  
    42.             else  
    43.             {  
    44.                 pThis->ShowWindow(SW_SHOW);  
    45.             }  
    46.             break;  
    47.         }  
    48.     default:  
    49.         {  
    50.             break;  
    51.         }  
    52.     }  
    53.   
    54.     return pDefProc(hwnd, uMsg, wParam, lParam);  
    55. }  

    好了,窗口消息机制处理完了,就要处理阴影画法了,我这里用的是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.   
    6. REAL szPos[3] = {0.0F, 0.05F, 1.0F};  
    7. brShadow.SetInterpolationColors(clrShadow, szPos, nCount);  
    8.   
    9. // Draw shadow.  
    10. rcShadow.Width  = rcShadow.Width - m_nShadowSize - m_nBlankArea;  
    11. rcShadow.Height = rcShadow.Height - m_nShadowSize - m_nBlankArea;  
    12. graphics.ExcludeClip(rcShadow);  
    13. 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

  • 相关阅读:
    第三次作业
    第二次作业
    第一次作业—编译原理概述
    第六次课堂作业——正规文法与正规式
    词法分析程序的设计与实现
    1702第四次作业(文法和语文总结与梳理)
    1702第三次作业(语法树,短语,直接短语,句柄)
    软工1702第一次作业(简述编译程序)
    random库的使用
    基本的字符串之切片
  • 原文地址:https://www.cnblogs.com/chechen/p/5644222.html
Copyright © 2020-2023  润新知