图片算法以及窗口阴影

来源:互联网 发布:淘宝客服经典话术大全 编辑:程序博客网 时间:2024/05/19 09:16

转载请说明原出处,谢谢:http://blog.csdn.net/zhuhongshu/article/details/42580877


         之前我写的程序使用阴影时,一直是使用codeproject网站上的WndShadow类,并且把它当作单独的模块来使用,后来觉得使用阴影的情况非常多,所以今天就把这个类改写了一下,让他融入到duilib,并且可以直接使用xml来描述阴影,不需要写任何c++代码。


        以前的WndShadow类是用算法来计算阴影,灵活性很大,但是缺点就是效果不够理想,所以我另外给他附加了使用图片素材来贴阴影的功能。最终的新类名为CShadowUI。这个类可以单独使用,我把他集成到了自己的库里。为了融合到Duilib我修改了UiLib.h文件、UIDlgBuilder.cpp文件、UIManager.h文件、UIManager.cpp文件。


        先贴两张效果图,以下是素材阴影和算法阴影的效果图:





        通过设置xml的Window标签可以添加阴影,阴影的xml属性描述如下:


[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <Attribute name="showshadow" default="false" type="BOOL" comment="是否启用窗体阴影"/>  
  2. <Attribute name="shadowimage" default="" type="STRING" comment="阴影图片,使用此属性后自动屏蔽算法阴影(不支持source等属性设置)"/>  
  3. <Attribute name="shadowcorner" default="0,0,0,0" type="RECT" comment="图片阴影的九宫格描述"/>  
  4. <Attribute name="shadowsize" default="0" type="BYTE" comment="算法阴影的宽度(-20到20)"/>  
  5. <Attribute name="shadowsharpness" default="255" type="BYTE" comment="算法阴影的锐度"/>  
  6. <Attribute name="shadowdarkness" default="255" type="BYTE" comment="算法阴影的深度(相当于透明度)"/>  
  7. <Attribute name="shadowposition" default="0,0" type="SIZE" comment="算法阴影的偏移量"/>  
  8. <Attribute name="shadowcolor" default="0x000000" type="DWORD" comment="算法阴影的颜色,RGB格式,不支持透明度,使用shadowdarkness设置透明度"/>  

        前面的两个效果图的对应xml描述如下:


[html] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. <!-- 图片阴影 -->  
  2. <Window size="840,600" sizebox="4,4,4,4" caption="0,0,0,75" mininfo="840,600" showshadow="true" shadowimage="shadow.png" shadowcorner="23,13,23,33">  
  3. <!-- 算法阴影 -->  
  4. <Window size="840,600" sizebox="4,4,4,4" caption="0,0,0,75" mininfo="840,600" showshadow="true" shadowsize="5" shadowposition="1,1" shadowcolor="#333333">  


源码:


       UIShadow.h源码为:


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. // WndShadow.h : header file  
  2. //  
  3. // Version 0.1  
  4. //  
  5. // Copyright (c) 2006 Perry Zhu, All Rights Reserved.  
  6. //  
  7. // mailto:perry@live.com  
  8. //  
  9. //  
  10. // This source file may be redistributed unmodified by any means PROVIDING   
  11. // it is NOT sold for profit without the authors expressed written   
  12. // consent, and providing that this notice and the author's name and all   
  13. // copyright notices remain intact. This software is by no means to be   
  14. // included as part of any third party components library, or as part any  
  15. // development solution that offers MFC extensions that are sold for profit.   
  16. //   
  17. // If the source code is used in any commercial applications then a statement   
  18. // along the lines of:  
  19. //   
  20. // "Portions Copyright (c) 2006 Perry Zhu" must be included in the "Startup   
  21. // Banner", "About Box" or "Printed Documentation". This software is provided   
  22. // "as is" without express or implied warranty. Use it at your own risk! The   
  23. // author accepts no liability for any damage/loss of business that this   
  24. // product may cause.  
  25. //  
  26. /////////////////////////////////////////////////////////////////////////////  
  27. //****************************************************************************  
  28.   
  29. /********************************************************************  
  30.     created:    2015/01/09  
  31.     filename:   UIShadow.h  
  32.     author:     Redrain  
  33.       
  34.     purpose:    DuiLib阴影类,在原WndShadow类的基础上,增加了通过PNG图片设置阴影的功能,并且把代码与DuiLib融合  
  35. *********************************************************************/  
  36.   
  37. #ifndef __UISHADOW_H__  
  38. #define __UISHADOW_H__  
  39.   
  40. #pragma once  
  41. #include "map"  
  42.   
  43. namespace DuiLib  
  44. {  
  45. typedef BOOL (WINAPI *pfnUpdateLayeredWindow)(HWND hWnd, HDC hdcDst, POINT *pptDst,  
  46.         SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey,  
  47.         BLENDFUNCTION *pblend, DWORD dwFlags);  
  48.   
  49. class UILIB_API CShadowUI  
  50. {  
  51. public:  
  52.     friend class CPaintManagerUI;  
  53.   
  54.     CShadowUI(void);  
  55.     virtual ~CShadowUI(void);  
  56.   
  57. public:  
  58.     // bShow为真时才会创建阴影  
  59.     void ShowShadow(bool bShow);      
  60.     bool IsShowShadow() const;  
  61.   
  62.     // 算法阴影的函数  
  63.     bool SetSize(int NewSize = 0);  
  64.     bool SetSharpness(unsigned int NewSharpness = 5);  
  65.     bool SetDarkness(unsigned int NewDarkness = 200);  
  66.     bool SetPosition(int NewXOffset = 5, int NewYOffset = 5);  
  67.     bool SetColor(COLORREF NewColor = 0);  
  68.   
  69.     // 图片阴影的函数  
  70.     bool SetImage(LPCTSTR szImage);  
  71.     bool SetShadowCorner(RECT rcCorner);    // 九宫格方式描述阴影  
  72.       
  73. protected:  
  74.   
  75.     //  初始化并注册阴影类  
  76.     static bool Initialize(HINSTANCE hInstance);  
  77.   
  78.     //  创建阴影窗体,由CPaintManagerUI自动调用  
  79.     void Create(CPaintManagerUI* pPaintManager);  
  80.   
  81.     //  子类化父窗体  
  82.     static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);  
  83.   
  84.     // 父窗体改变大小,移动,或者主动重绘阴影时调用  
  85.     void Update(HWND hParent);  
  86.   
  87.     // 通过算法计算阴影  
  88.     void MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent);  
  89.   
  90.     // 计算alpha预乘值  
  91.     inline DWORD PreMultiply(COLORREF cl, unsigned char nAlpha)  
  92.     {  
  93.         return (GetRValue(cl) * (DWORD)nAlpha / 255) |  
  94.             (GetGValue(cl) * (DWORD)nAlpha / 255) << 8 |  
  95.             (GetBValue(cl) * (DWORD)nAlpha / 255) << 16 ;  
  96.     }  
  97.   
  98. protected:  
  99.     enum ShadowStatus  
  100.     {  
  101.         SS_ENABLED = 1,             // Shadow is enabled, if not, the following one is always false  
  102.         SS_VISABLE = 1 << 1,      // Shadow window is visible  
  103.         SS_PARENTVISIBLE = 1<< 2  // Parent window is visible, if not, the above one is always false  
  104.     };  
  105.   
  106.     // 保存已经附加的窗体句柄和与其关联的阴影类,方便在ParentProc()函数中通过句柄得到阴影类  
  107.     static std::map<HWND, CShadowUI *> *s_Shadowmap;  
  108.     static bool s_bHasInit;  
  109.   
  110.     CPaintManagerUI *m_pManager;        // 父窗体的CPaintManagerUI,用来获取素材资源和父窗体句柄  
  111.     HWND             m_hWnd;            // 阴影窗体的句柄  
  112.     LONG             m_OriParentProc;   // 子类化父窗体  
  113.     BYTE             m_Status;  
  114.     bool             m_bIsImageMode;    // 是否为图片阴影模式  
  115.     bool             m_bIsShowShadow;   // 是否要显示阴影  
  116.   
  117.     // 算法阴影成员变量  
  118.     unsigned char m_nDarkness;  // Darkness, transparency of blurred area  
  119.     unsigned char m_nSharpness; // Sharpness, width of blurred border of shadow window  
  120.     signed char m_nSize;    // Shadow window size, relative to parent window size  
  121.   
  122.     // The X and Y offsets of shadow window,  
  123.     // relative to the parent window, at center of both windows (not top-left corner), signed  
  124.     signed char m_nxOffset;  
  125.     signed char m_nyOffset;  
  126.   
  127.     // Restore last parent window size, used to determine the update strategy when parent window is resized  
  128.     LPARAM m_WndSize;  
  129.   
  130.     // Set this to true if the shadow should not be update until next WM_PAINT is received  
  131.     bool m_bUpdate;  
  132.   
  133.     COLORREF m_Color;   // Color of shadow  
  134.   
  135.     // 图片阴影成员变量  
  136.     CDuiString  m_sShadowImage;  
  137.     RECT        m_rcShadowCorner;  
  138. };  
  139.   
  140. }  
  141.   
  142. #endif //__UISHADOW_H__  



       UIShadow.cpp源码为:


[cpp] view plain copy
 在CODE上查看代码片派生到我的代码片
  1. #include "StdAfx.h"  
  2. #include "UIShadow.h"  
  3. #include "math.h"  
  4. #include "crtdbg.h"  
  5. #include "Core/UIManager.h"  
  6.   
  7. namespace DuiLib  
  8. {  
  9.   
  10. const TCHAR *strWndClassName = _T("PerryShadowWnd");  
  11. std::map<HWND, CShadowUI *>* CShadowUI::s_Shadowmap = new std::map<HWND, CShadowUI *>;  
  12. bool CShadowUI::s_bHasInit = FALSE;  
  13.   
  14. CShadowUI::CShadowUI(void)  
  15. : m_hWnd((HWND)NULL)  
  16. , m_OriParentProc(NULL)  
  17. , m_nDarkness(150)  
  18. , m_nSharpness(5)  
  19. , m_nSize(0)  
  20. , m_nxOffset(0)  
  21. , m_nyOffset(0)  
  22. , m_Color(RGB(0, 0, 0))  
  23. , m_WndSize(0)  
  24. , m_bUpdate(false)  
  25. , m_bIsImageMode(false)  
  26. , m_bIsShowShadow(false)  
  27. {  
  28.     ::ZeroMemory(&m_rcShadowCorner, sizeof(RECT));  
  29. }  
  30.   
  31. CShadowUI::~CShadowUI(void)  
  32. {  
  33. }  
  34.   
  35. bool CShadowUI::Initialize(HINSTANCE hInstance)  
  36. {  
  37.     if (s_bHasInit)  
  38.         return false;  
  39.   
  40.     // Register window class for shadow window  
  41.     WNDCLASSEX wcex;  
  42.   
  43.     memset(&wcex, 0, sizeof(wcex));  
  44.   
  45.     wcex.cbSize = sizeof(WNDCLASSEX);   
  46.     wcex.style          = CS_HREDRAW | CS_VREDRAW;  
  47.     wcex.lpfnWndProc    = DefWindowProc;  
  48.     wcex.cbClsExtra     = 0;  
  49.     wcex.cbWndExtra     = 0;  
  50.     wcex.hInstance      = hInstance;  
  51.     wcex.hIcon          = NULL;  
  52.     wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);  
  53.     wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);  
  54.     wcex.lpszMenuName   = NULL;  
  55.     wcex.lpszClassName  = strWndClassName;  
  56.     wcex.hIconSm        = NULL;  
  57.   
  58.     RegisterClassEx(&wcex);  
  59.   
  60.     s_bHasInit = true;  
  61.     return true;  
  62. }  
  63.   
  64. void CShadowUI::Create(CPaintManagerUI* pPaintManager)  
  65. {  
  66.     if(!m_bIsShowShadow)  
  67.         return;  
  68.   
  69.     // Already initialized  
  70.     _ASSERT(CPaintManagerUI::GetInstance() != INVALID_HANDLE_VALUE);  
  71.     _ASSERT(pPaintManager != NULL);  
  72.     m_pManager = pPaintManager;  
  73.     HWND hParentWnd = m_pManager->GetPaintWindow();  
  74.     // Add parent window - shadow pair to the map  
  75.     _ASSERT(s_Shadowmap->find(hParentWnd) == s_Shadowmap->end()); // Only one shadow for each window  
  76.     (*s_Shadowmap)[hParentWnd] = this;  
  77.   
  78.     // Determine the initial show state of shadow according to parent window's state  
  79.     LONG lParentStyle = GetWindowLong(hParentWnd, GWL_STYLE);  
  80.   
  81.     // Create the shadow window  
  82.     LONG styleValue = lParentStyle & WS_CAPTION;  
  83.     m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,  
  84.         /*WS_VISIBLE | */styleValue | WS_POPUPWINDOW,  
  85.         CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, CPaintManagerUI::GetInstance(), NULL);  
  86.   
  87.     if(!(WS_VISIBLE & lParentStyle))    // Parent invisible  
  88.         m_Status = SS_ENABLED;  
  89.     else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow  
  90.         m_Status = SS_ENABLED | SS_PARENTVISIBLE;  
  91.     else    // Show the shadow  
  92.     {  
  93.         m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;  
  94.         ::ShowWindow(m_hWnd, SW_SHOWNA);  
  95.         Update(hParentWnd);  
  96.     }  
  97.   
  98.     // Replace the original WndProc of parent window to steal messages  
  99.     m_OriParentProc = GetWindowLong(hParentWnd, GWL_WNDPROC);  
  100.   
  101. #pragma warning(disable: 4311)  // temporrarily disable the type_cast warning in Win32  
  102.     SetWindowLong(hParentWnd, GWL_WNDPROC, (LONG)ParentProc);  
  103. #pragma warning(default: 4311)  
  104.   
  105. }  
  106.   
  107. LRESULT CALLBACK CShadowUI::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  108. {  
  109.     _ASSERT(s_Shadowmap->find(hwnd) != s_Shadowmap->end());   // Shadow must have been attached  
  110.   
  111.     CShadowUI *pThis = (*s_Shadowmap)[hwnd];  
  112.   
  113.     switch(uMsg)  
  114.     {  
  115.     case WM_MOVE:  
  116.         if(pThis->m_Status & SS_VISABLE)  
  117.         {  
  118.             RECT WndRect;  
  119.             GetWindowRect(hwnd, &WndRect);  
  120.             if (pThis->m_bIsImageMode)  
  121.             {  
  122.                 SetWindowPos(pThis->m_hWnd, 0,  
  123.                     WndRect.left - pThis->m_rcShadowCorner.left, WndRect.top - pThis->m_rcShadowCorner.top,  
  124.                     0, 0, SWP_NOSIZE | SWP_NOACTIVATE);  
  125.             }  
  126.             else  
  127.             {  
  128.                 SetWindowPos(pThis->m_hWnd, 0,  
  129.                     WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize,  
  130.                     0, 0, SWP_NOSIZE | SWP_NOACTIVATE);  
  131.             }  
  132.         }  
  133.         break;  
  134.   
  135.     case WM_SIZE:  
  136.         if(pThis->m_Status & SS_ENABLED)  
  137.         {  
  138.             if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam)  
  139.             {  
  140.                 ::ShowWindow(pThis->m_hWnd, SW_HIDE);  
  141.                 pThis->m_Status &= ~SS_VISABLE;  
  142.             }  
  143.             else if(pThis->m_Status & SS_PARENTVISIBLE)  // Parent maybe resized even if invisible  
  144.             {  
  145.                 // Awful! It seems that if the window size was not decreased  
  146.                 // the window region would never be updated until WM_PAINT was sent.  
  147.                 // So do not Update() until next WM_PAINT is received in this case  
  148.                 if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))  
  149.                     pThis->m_bUpdate = true;  
  150.                 else  
  151.                     pThis->Update(hwnd);  
  152.                 if(!(pThis->m_Status & SS_VISABLE))  
  153.                 {  
  154.                     ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);  
  155.                     pThis->m_Status |= SS_VISABLE;  
  156.                 }  
  157.             }  
  158.             pThis->m_WndSize = lParam;  
  159.         }  
  160.         break;  
  161.   
  162.     case WM_PAINT:  
  163.         {  
  164.             if(pThis->m_bUpdate)  
  165.             {  
  166.                 pThis->Update(hwnd);  
  167.                 pThis->m_bUpdate = false;  
  168.             }  
  169.             //return hr;  
  170.             break;  
  171.         }  
  172.   
  173.         // In some cases of sizing, the up-right corner of the parent window region would not be properly updated  
  174.         // Update() again when sizing is finished  
  175.     case WM_EXITSIZEMOVE:  
  176.         if(pThis->m_Status & SS_VISABLE)  
  177.         {  
  178.             pThis->Update(hwnd);  
  179.         }  
  180.         break;  
  181.   
  182.     case WM_SHOWWINDOW:  
  183.         if(pThis->m_Status & SS_ENABLED)  
  184.         {  
  185.             if(!wParam) // the window is being hidden  
  186.             {  
  187.                 ::ShowWindow(pThis->m_hWnd, SW_HIDE);  
  188.                 pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);  
  189.             }  
  190.             else if(!(pThis->m_Status & SS_PARENTVISIBLE))  
  191.             {  
  192.                 //pThis->Update(hwnd);  
  193.                 pThis->m_bUpdate = true;  
  194.                 ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);  
  195.                 pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;  
  196.             }  
  197.         }  
  198.         break;  
  199.   
  200.     case WM_DESTROY:  
  201.         DestroyWindow(pThis->m_hWnd);    // Destroy the shadow  
  202.         break;  
  203.           
  204.     case WM_NCDESTROY:  
  205.         s_Shadowmap->erase(hwnd);    // Remove this window and shadow from the map  
  206.         break;  
  207.   
  208.     }  
  209.   
  210.   
  211. #pragma warning(disable: 4312)  // temporrarily disable the type_cast warning in Win32  
  212.     // Call the default(original) window procedure for other messages or messages processed but not returned  
  213.     return ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);  
  214. #pragma warning(default: 4312)  
  215.   
  216. }  
  217.   
  218. void CShadowUI::Update(HWND hParent)  
  219. {  
  220.   
  221.     RECT WndRect;  
  222.     GetWindowRect(hParent, &WndRect);  
  223.     int nShadWndWid;  
  224.     int nShadWndHei;  
  225.     if (m_bIsImageMode)  
  226.     {  
  227.         if(m_sShadowImage.IsEmpty())  
  228.             return;  
  229.   
  230.         nShadWndWid = WndRect.right - WndRect.left + m_rcShadowCorner.left + m_rcShadowCorner.right;  
  231.         nShadWndHei = WndRect.bottom - WndRect.top + m_rcShadowCorner.top + m_rcShadowCorner.bottom;  
  232.     }  
  233.     else  
  234.     {  
  235.         nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;  
  236.         nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;  
  237.     }  
  238.           
  239.     // Create the alpha blending bitmap  
  240.     BITMAPINFO bmi;        // bitmap header  
  241.   
  242.     ZeroMemory(&bmi, sizeof(BITMAPINFO));  
  243.     bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);  
  244.     bmi.bmiHeader.biWidth = nShadWndWid;  
  245.     bmi.bmiHeader.biHeight = nShadWndHei;  
  246.     bmi.bmiHeader.biPlanes = 1;  
  247.     bmi.bmiHeader.biBitCount = 32;         // four 8-bit components  
  248.     bmi.bmiHeader.biCompression = BI_RGB;  
  249.     bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;  
  250.   
  251.     BYTE *pvBits;          // pointer to DIB section  
  252.     HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);  
  253.     HDC hMemDC = CreateCompatibleDC(NULL);  
  254.     HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);  
  255.   
  256.     if (m_bIsImageMode)  
  257.     {  
  258.         RECT rcPaint = {0, 0, nShadWndWid, nShadWndHei};  
  259.           
  260.         const TImageInfo* data = m_pManager->GetImageEx((LPCTSTR)m_sShadowImage, NULL, 0);  
  261.   
  262.         if( !data )   
  263.             return;      
  264.   
  265.         RECT rcBmpPart = {0};  
  266.         rcBmpPart.right = data->nX;  
  267.         rcBmpPart.bottom = data->nY;  
  268.   
  269.         CRenderEngine::DrawImage(hMemDC, data->hBitmap, rcPaint, rcPaint, rcBmpPart, m_rcShadowCorner, data->alphaChannel, 0xFF, truefalsefalse);  
  270.   
  271.     }  
  272.     else  
  273.     {  
  274.         ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);  
  275.         MakeShadow((UINT32 *)pvBits, hParent, &WndRect);  
  276.     }  
  277.   
  278.     POINT ptDst;  
  279.     if (m_bIsImageMode)  
  280.     {  
  281.         ptDst.x = WndRect.left - m_rcShadowCorner.left;  
  282.         ptDst.y = WndRect.top - m_rcShadowCorner.top;  
  283.     }  
  284.     else  
  285.     {  
  286.         ptDst.x = WndRect.left + m_nxOffset - m_nSize;  
  287.         ptDst.y = WndRect.top + m_nyOffset - m_nSize;  
  288.     }  
  289.   
  290.     POINT ptSrc = {0, 0};  
  291.     SIZE WndSize = {nShadWndWid, nShadWndHei};  
  292.     BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };  
  293.   
  294.     MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);  
  295.   
  296.     BOOL bRet= ::UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC,  
  297.         &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);  
  298.   
  299.     _ASSERT(bRet); // something was wrong....  
  300.   
  301.     // Delete used resources  
  302.     SelectObject(hMemDC, hOriBmp);  
  303.     DeleteObject(hbitmap);  
  304.     DeleteDC(hMemDC);  
  305.   
  306. }  
  307.   
  308. void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)  
  309. {  
  310.     // The shadow algorithm:  
  311.     // Get the region of parent window,  
  312.     // Apply morphologic erosion to shrink it into the size (ShadowWndSize - Sharpness)  
  313.     // Apply modified (with blur effect) morphologic dilation to make the blurred border  
  314.     // The algorithm is optimized by assuming parent window is just "one piece" and without "wholes" on it  
  315.   
  316.     // Get the region of parent window,  
  317.     HRGN hParentRgn = CreateRectRgn(0, 0, 0, 0);  
  318.     GetWindowRgn(hParent, hParentRgn);  
  319.   
  320.     // Determine the Start and end point of each horizontal scan line  
  321.     SIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};  
  322.     SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};  
  323.     // Extra 2 lines (set to be empty) in ptAnchors are used in dilation  
  324.     int nAnchors = max(szParent.cy, szShadow.cy);   // # of anchor points pares  
  325.     int (*ptAnchors)[2] = new int[nAnchors + 2][2];  
  326.     int (*ptAnchorsOri)[2] = new int[szParent.cy][2];   // anchor points, will not modify during erosion  
  327.     ptAnchors[0][0] = szParent.cx;  
  328.     ptAnchors[0][1] = 0;  
  329.     ptAnchors[nAnchors + 1][0] = szParent.cx;  
  330.     ptAnchors[nAnchors + 1][1] = 0;  
  331.     if(m_nSize > 0)  
  332.     {  
  333.         // Put the parent window anchors at the center  
  334.         for(int i = 0; i < m_nSize; i++)  
  335.         {  
  336.             ptAnchors[i + 1][0] = szParent.cx;  
  337.             ptAnchors[i + 1][1] = 0;  
  338.             ptAnchors[szShadow.cy - i][0] = szParent.cx;  
  339.             ptAnchors[szShadow.cy - i][1] = 0;  
  340.         }  
  341.         ptAnchors += m_nSize;  
  342.     }  
  343.     for(int i = 0; i < szParent.cy; i++)  
  344.     {  
  345.         // find start point  
  346.         int j;  
  347.         for(j = 0; j < szParent.cx; j++)  
  348.         {  
  349.             if(PtInRegion(hParentRgn, j, i))  
  350.             {  
  351.                 ptAnchors[i + 1][0] = j + m_nSize;  
  352.                 ptAnchorsOri[i][0] = j;  
  353.                 break;  
  354.             }  
  355.         }  
  356.   
  357.         if(j >= szParent.cx) // Start point not found  
  358.         {  
  359.             ptAnchors[i + 1][0] = szParent.cx;  
  360.             ptAnchorsOri[i][1] = 0;  
  361.             ptAnchors[i + 1][0] = szParent.cx;  
  362.             ptAnchorsOri[i][1] = 0;  
  363.         }  
  364.         else  
  365.         {  
  366.             // find end point  
  367.             for(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--)  
  368.             {  
  369.                 if(PtInRegion(hParentRgn, j, i))  
  370.                 {  
  371.                     ptAnchors[i + 1][1] = j + 1 + m_nSize;  
  372.                     ptAnchorsOri[i][1] = j + 1;  
  373.                     break;  
  374.                 }  
  375.             }  
  376.         }  
  377.     }  
  378.   
  379.     if(m_nSize > 0)  
  380.         ptAnchors -= m_nSize;   // Restore pos of ptAnchors for erosion  
  381.     int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2];  // Store the result of erosion  
  382.     // First and last line should be empty  
  383.     ptAnchorsTmp[0][0] = szParent.cx;  
  384.     ptAnchorsTmp[0][1] = 0;  
  385.     ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;  
  386.     ptAnchorsTmp[nAnchors + 1][1] = 0;  
  387.     int nEroTimes = 0;  
  388.     // morphologic erosion  
  389.     for(int i = 0; i < m_nSharpness - m_nSize; i++)  
  390.     {  
  391.         nEroTimes++;  
  392.         //ptAnchorsTmp[1][0] = szParent.cx;  
  393.         //ptAnchorsTmp[1][1] = 0;  
  394.         //ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;  
  395.         //ptAnchorsTmp[szParent.cy + 1][1] = 0;  
  396.         for(int j = 1; j < nAnchors + 1; j++)  
  397.         {  
  398.             ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;  
  399.             ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;  
  400.         }  
  401.         // Exchange ptAnchors and ptAnchorsTmp;  
  402.         int (*ptAnchorsXange)[2] = ptAnchorsTmp;  
  403.         ptAnchorsTmp = ptAnchors;  
  404.         ptAnchors = ptAnchorsXange;  
  405.     }  
  406.   
  407.     // morphologic dilation  
  408.     ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1;   // now coordinates in ptAnchors are same as in shadow window  
  409.     // Generate the kernel  
  410.     int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;  
  411.     int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;  
  412.     UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];  
  413.     UINT32 *pKernelIter = pKernel;  
  414.     for(int i = 0; i <= 2 * nKernelSize; i++)  
  415.     {  
  416.         for(int j = 0; j <= 2 * nKernelSize; j++)  
  417.         {  
  418.             double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));  
  419.             if(dLength < nCenterSize)  
  420.                 *pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);  
  421.             else if(dLength <= nKernelSize)  
  422.             {  
  423.                 UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));  
  424.                 *pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);  
  425.             }  
  426.             else  
  427.                 *pKernelIter = 0;  
  428.             //TRACE("%d ", *pKernelIter >> 24);  
  429.             pKernelIter ++;  
  430.         }  
  431.         //TRACE("\n");  
  432.     }  
  433.     // Generate blurred border  
  434.     for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)  
  435.     {  
  436.         int j;  
  437.         if(ptAnchors[i][0] < ptAnchors[i][1])  
  438.         {  
  439.   
  440.             // Start of line  
  441.             for(j = ptAnchors[i][0];  
  442.                 j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]);  
  443.                 j++)  
  444.             {  
  445.                 for(int k = 0; k <= 2 * nKernelSize; k++)  
  446.                 {  
  447.                     UINT32 *pPixel = pShadBits +  
  448.                         (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;  
  449.                     UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);  
  450.                     for(int l = 0; l <= 2 * nKernelSize; l++)  
  451.                     {  
  452.                         if(*pPixel < *pKernelPixel)  
  453.                             *pPixel = *pKernelPixel;  
  454.                         pPixel++;  
  455.                         pKernelPixel++;  
  456.                     }  
  457.                 }  
  458.             }   // for() start of line  
  459.   
  460.             // End of line  
  461.             for(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1);  
  462.                 j < ptAnchors[i][1];  
  463.                 j++)  
  464.             {  
  465.                 for(int k = 0; k <= 2 * nKernelSize; k++)  
  466.                 {  
  467.                     UINT32 *pPixel = pShadBits +  
  468.                         (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;  
  469.                     UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);  
  470.                     for(int l = 0; l <= 2 * nKernelSize; l++)  
  471.                     {  
  472.                         if(*pPixel < *pKernelPixel)  
  473.                             *pPixel = *pKernelPixel;  
  474.                         pPixel++;  
  475.                         pKernelPixel++;  
  476.                     }  
  477.                 }  
  478.             }   // for() end of line  
  479.   
  480.         }  
  481.     }   // for() Generate blurred border  
  482.   
  483.     // Erase unwanted parts and complement missing  
  484.     UINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);  
  485.     for(int i = min(nKernelSize, max(m_nSize - m_nyOffset, 0));  
  486.         i < max(szShadow.cy - nKernelSize, min(szParent.cy + m_nSize - m_nyOffset, szParent.cy + 2 * m_nSize));  
  487.         i++)  
  488.     {  
  489.         UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;  
  490.         if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy)   // Line is not covered by parent window  
  491.         {  
  492.             for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++)  
  493.             {  
  494.                 *(pLine + j) = clCenter;  
  495.             }  
  496.         }  
  497.         else  
  498.         {  
  499.             for(int j = ptAnchors[i][0];  
  500.                 j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]);  
  501.                 j++)  
  502.                 *(pLine + j) = clCenter;  
  503.             for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, 0);  
  504.                 j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, szShadow.cx);  
  505.                 j++)  
  506.                 *(pLine + j) = 0;  
  507.             for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]);  
  508.                 j < ptAnchors[i][1];  
  509.                 j++)  
  510.                 *(pLine + j) = clCenter;  
  511.         }  
  512.     }  
  513.   
  514.     // Delete used resources  
  515.     delete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);  
  516.     delete[] ptAnchorsTmp;  
  517.     delete[] ptAnchorsOri;  
  518.     delete[] pKernel;  
  519.     DeleteObject(hParentRgn);  
  520. }  
  521.   
  522. void CShadowUI::ShowShadow(bool bShow)  
  523. {  
  524.     m_bIsShowShadow = bShow;  
  525. }  
  526.   
  527. bool CShadowUI::IsShowShadow() const  
  528. {  
  529.     return m_bIsShowShadow;  
  530. }  
  531.   
  532. bool CShadowUI::SetSize(int NewSize)  
  533. {  
  534.     if(NewSize > 20 || NewSize < -20)  
  535.         return false;  
  536.   
  537.     m_nSize = (signed char)NewSize;  
  538.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  539.         Update(GetParent(m_hWnd));  
  540.     return true;  
  541. }  
  542.   
  543. bool CShadowUI::SetSharpness(unsigned int NewSharpness)  
  544. {  
  545.     if(NewSharpness > 20)  
  546.         return false;  
  547.   
  548.     m_nSharpness = (unsigned char)NewSharpness;  
  549.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  550.         Update(GetParent(m_hWnd));  
  551.     return true;  
  552. }  
  553.   
  554. bool CShadowUI::SetDarkness(unsigned int NewDarkness)  
  555. {  
  556.     if(NewDarkness > 255)  
  557.         return false;  
  558.   
  559.     m_nDarkness = (unsigned char)NewDarkness;  
  560.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  561.         Update(GetParent(m_hWnd));  
  562.     return true;  
  563. }  
  564.   
  565. bool CShadowUI::SetPosition(int NewXOffset, int NewYOffset)  
  566. {  
  567.     if(NewXOffset > 20 || NewXOffset < -20 ||  
  568.         NewYOffset > 20 || NewYOffset < -20)  
  569.         return false;  
  570.       
  571.     m_nxOffset = (signed char)NewXOffset;  
  572.     m_nyOffset = (signed char)NewYOffset;  
  573.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  574.         Update(GetParent(m_hWnd));  
  575.     return true;  
  576. }  
  577.   
  578. bool CShadowUI::SetColor(COLORREF NewColor)  
  579. {  
  580.     m_Color = NewColor;  
  581.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  582.         Update(GetParent(m_hWnd));  
  583.     return true;  
  584. }  
  585.   
  586. bool CShadowUI::SetImage(LPCTSTR szImage)  
  587. {  
  588.     if (szImage == NULL)  
  589.         return false;  
  590.   
  591.     m_bIsImageMode = true;  
  592.     m_sShadowImage = szImage;  
  593.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  594.         Update(GetParent(m_hWnd));  
  595.   
  596.     return true;  
  597. }  
  598. bool CShadowUI::SetShadowCorner(RECT rcCorner)  
  599. {  
  600.     if (rcCorner.left < 0 || rcCorner.top < 0 || rcCorner.right < 0 || rcCorner.bottom < 0)  
  601.         return false;  
  602.   
  603.     m_rcShadowCorner = rcCorner;  
  604.   
  605.     if(m_hWnd != NULL && (SS_VISABLE & m_Status))  
  606.         Update(GetParent(m_hWnd));  
  607.   
  608.     return true;  
  609. }  
  610.   
  611. //namespace DuiLib  


总结:


      这个阴影使用双层窗体实现的,可以避免duilib在半透明窗体上的不足。但也由于使用双层窗体,导致窗体大小快速改变时会看出阴影改变的延迟 ,能不能接受这个延迟就看个人了,所以如果是固定大小的窗体使用阴影效果最好。具体的效果可以看我的demo。


      完整的修改版的库代码和阴影的demo,可以下载我的库:点击打开链接

0 0