duilib 使用图片素材或者算法给窗体增加阴影(源码和demo)

来源:互联网 发布:绝地网络延迟检测 编辑:程序博客网 时间:2024/06/05 00:06

转载请说明原出处,谢谢: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属性描述如下:


<Attribute name="showshadow" default="false" type="BOOL" comment="是否启用窗体阴影"/><Attribute name="shadowimage" default="" type="STRING" comment="阴影图片,使用此属性后自动屏蔽算法阴影(不支持source等属性设置)"/><Attribute name="shadowcorner" default="0,0,0,0" type="RECT" comment="图片阴影的九宫格描述"/><Attribute name="shadowsize" default="0" type="BYTE" comment="算法阴影的宽度(-20到20)"/><Attribute name="shadowsharpness" default="255" type="BYTE" comment="算法阴影的锐度"/><Attribute name="shadowdarkness" default="255" type="BYTE" comment="算法阴影的深度(相当于透明度)"/><Attribute name="shadowposition" default="0,0" type="SIZE" comment="算法阴影的偏移量"/><Attribute name="shadowcolor" default="0x000000" type="DWORD" comment="算法阴影的颜色,RGB格式,不支持透明度,使用shadowdarkness设置透明度"/>

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


<!-- 图片阴影 --><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"><!-- 算法阴影 --><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源码为:


// WndShadow.h : header file//// Version 0.1//// Copyright (c) 2006 Perry Zhu, All Rights Reserved.//// mailto:perry@live.com////// This source file may be redistributed unmodified by any means PROVIDING // it is NOT sold for profit without the authors expressed written // consent, and providing that this notice and the author's name and all // copyright notices remain intact. This software is by no means to be // included as part of any third party components library, or as part any// development solution that offers MFC extensions that are sold for profit. // // If the source code is used in any commercial applications then a statement // along the lines of:// // "Portions Copyright (c) 2006 Perry Zhu" must be included in the "Startup // Banner", "About Box" or "Printed Documentation". This software is provided // "as is" without express or implied warranty. Use it at your own risk! The // author accepts no liability for any damage/loss of business that this // product may cause./////////////////////////////////////////////////////////////////////////////////****************************************************************************/********************************************************************created:2015/01/09filename: UIShadow.hauthor:Redrainpurpose:DuiLib阴影类,在原WndShadow类的基础上,增加了通过PNG图片设置阴影的功能,并且把代码与DuiLib融合*********************************************************************/#ifndef __UISHADOW_H__#define __UISHADOW_H__#pragma once#include "map"namespace DuiLib{typedef BOOL (WINAPI *pfnUpdateLayeredWindow)(HWND hWnd, HDC hdcDst, POINT *pptDst,SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey,BLENDFUNCTION *pblend, DWORD dwFlags);class UILIB_API CShadowUI{public:friend class CPaintManagerUI;CShadowUI(void);virtual ~CShadowUI(void);public:// bShow为真时才会创建阴影void ShowShadow(bool bShow);bool IsShowShadow() const;// 算法阴影的函数bool SetSize(int NewSize = 0);bool SetSharpness(unsigned int NewSharpness = 5);bool SetDarkness(unsigned int NewDarkness = 200);bool SetPosition(int NewXOffset = 5, int NewYOffset = 5);bool SetColor(COLORREF NewColor = 0);// 图片阴影的函数bool SetImage(LPCTSTR szImage);bool SetShadowCorner(RECT rcCorner);// 九宫格方式描述阴影protected://初始化并注册阴影类static bool Initialize(HINSTANCE hInstance);//创建阴影窗体,由CPaintManagerUI自动调用void Create(CPaintManagerUI* pPaintManager);//子类化父窗体static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);// 父窗体改变大小,移动,或者主动重绘阴影时调用void Update(HWND hParent);// 通过算法计算阴影void MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent);// 计算alpha预乘值inline DWORD PreMultiply(COLORREF cl, unsigned char nAlpha){return (GetRValue(cl) * (DWORD)nAlpha / 255) |(GetGValue(cl) * (DWORD)nAlpha / 255) << 8 |(GetBValue(cl) * (DWORD)nAlpha / 255) << 16 ;}protected:enum ShadowStatus{SS_ENABLED = 1,// Shadow is enabled, if not, the following one is always falseSS_VISABLE = 1 << 1,// Shadow window is visibleSS_PARENTVISIBLE = 1<< 2// Parent window is visible, if not, the above one is always false};// 保存已经附加的窗体句柄和与其关联的阴影类,方便在ParentProc()函数中通过句柄得到阴影类static std::map<HWND, CShadowUI *> *s_Shadowmap;static bool s_bHasInit;CPaintManagerUI*m_pManager;// 父窗体的CPaintManagerUI,用来获取素材资源和父窗体句柄HWND m_hWnd;// 阴影窗体的句柄LONG m_OriParentProc;// 子类化父窗体BYTE m_Status;bool m_bIsImageMode;// 是否为图片阴影模式bool m_bIsShowShadow;// 是否要显示阴影// 算法阴影成员变量unsigned char m_nDarkness;// Darkness, transparency of blurred areaunsigned char m_nSharpness;// Sharpness, width of blurred border of shadow windowsigned char m_nSize;// Shadow window size, relative to parent window size// The X and Y offsets of shadow window,// relative to the parent window, at center of both windows (not top-left corner), signedsigned char m_nxOffset;signed char m_nyOffset;// Restore last parent window size, used to determine the update strategy when parent window is resizedLPARAM m_WndSize;// Set this to true if the shadow should not be update until next WM_PAINT is receivedbool m_bUpdate;COLORREF m_Color;// Color of shadow// 图片阴影成员变量CDuiStringm_sShadowImage;RECTm_rcShadowCorner;};}#endif //__UISHADOW_H__



       UIShadow.cpp源码为:


#include "StdAfx.h"#include "UIShadow.h"#include "math.h"#include "crtdbg.h"#include "Core/UIManager.h"namespace DuiLib{const TCHAR *strWndClassName = _T("PerryShadowWnd");std::map<HWND, CShadowUI *>* CShadowUI::s_Shadowmap = new std::map<HWND, CShadowUI *>;bool CShadowUI::s_bHasInit = FALSE;CShadowUI::CShadowUI(void): m_hWnd((HWND)NULL), m_OriParentProc(NULL), m_nDarkness(150), m_nSharpness(5), m_nSize(0), m_nxOffset(0), m_nyOffset(0), m_Color(RGB(0, 0, 0)), m_WndSize(0), m_bUpdate(false), m_bIsImageMode(false), m_bIsShowShadow(false){::ZeroMemory(&m_rcShadowCorner, sizeof(RECT));}CShadowUI::~CShadowUI(void){}bool CShadowUI::Initialize(HINSTANCE hInstance){if (s_bHasInit)return false;// Register window class for shadow windowWNDCLASSEX wcex;memset(&wcex, 0, sizeof(wcex));wcex.cbSize = sizeof(WNDCLASSEX); wcex.style= CS_HREDRAW | CS_VREDRAW;wcex.lpfnWndProc= DefWindowProc;wcex.cbClsExtra= 0;wcex.cbWndExtra= 0;wcex.hInstance= hInstance;wcex.hIcon= NULL;wcex.hCursor= LoadCursor(NULL, IDC_ARROW);wcex.hbrBackground= (HBRUSH)(COLOR_WINDOW+1);wcex.lpszMenuName= NULL;wcex.lpszClassName= strWndClassName;wcex.hIconSm= NULL;RegisterClassEx(&wcex);s_bHasInit = true;return true;}void CShadowUI::Create(CPaintManagerUI* pPaintManager){if(!m_bIsShowShadow)return;// Already initialized_ASSERT(CPaintManagerUI::GetInstance() != INVALID_HANDLE_VALUE);_ASSERT(pPaintManager != NULL);m_pManager = pPaintManager;HWND hParentWnd = m_pManager->GetPaintWindow();// Add parent window - shadow pair to the map_ASSERT(s_Shadowmap->find(hParentWnd) == s_Shadowmap->end());// Only one shadow for each window(*s_Shadowmap)[hParentWnd] = this;// Determine the initial show state of shadow according to parent window's stateLONG lParentStyle = GetWindowLong(hParentWnd, GWL_STYLE);// Create the shadow windowLONG styleValue = lParentStyle & WS_CAPTION;m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,/*WS_VISIBLE | */styleValue | WS_POPUPWINDOW,CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, CPaintManagerUI::GetInstance(), NULL);if(!(WS_VISIBLE & lParentStyle))// Parent invisiblem_Status = SS_ENABLED;else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle)// Parent visible but does not need shadowm_Status = SS_ENABLED | SS_PARENTVISIBLE;else// Show the shadow{m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;::ShowWindow(m_hWnd, SW_SHOWNA);Update(hParentWnd);}// Replace the original WndProc of parent window to steal messagesm_OriParentProc = GetWindowLong(hParentWnd, GWL_WNDPROC);#pragma warning(disable: 4311)// temporrarily disable the type_cast warning in Win32SetWindowLong(hParentWnd, GWL_WNDPROC, (LONG)ParentProc);#pragma warning(default: 4311)}LRESULT CALLBACK CShadowUI::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam){_ASSERT(s_Shadowmap->find(hwnd) != s_Shadowmap->end());// Shadow must have been attachedCShadowUI *pThis = (*s_Shadowmap)[hwnd];switch(uMsg){case WM_MOVE:if(pThis->m_Status & SS_VISABLE){RECT WndRect;GetWindowRect(hwnd, &WndRect);if (pThis->m_bIsImageMode){SetWindowPos(pThis->m_hWnd, 0,WndRect.left - pThis->m_rcShadowCorner.left, WndRect.top - pThis->m_rcShadowCorner.top,0, 0, SWP_NOSIZE | SWP_NOACTIVATE);}else{SetWindowPos(pThis->m_hWnd, 0,WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize,0, 0, SWP_NOSIZE | SWP_NOACTIVATE);}}break;case WM_SIZE:if(pThis->m_Status & SS_ENABLED){if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam){::ShowWindow(pThis->m_hWnd, SW_HIDE);pThis->m_Status &= ~SS_VISABLE;}else if(pThis->m_Status & SS_PARENTVISIBLE)// Parent maybe resized even if invisible{// Awful! It seems that if the window size was not decreased// the window region would never be updated until WM_PAINT was sent.// So do not Update() until next WM_PAINT is received in this caseif(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))pThis->m_bUpdate = true;elsepThis->Update(hwnd);if(!(pThis->m_Status & SS_VISABLE)){::ShowWindow(pThis->m_hWnd, SW_SHOWNA);pThis->m_Status |= SS_VISABLE;}}pThis->m_WndSize = lParam;}break;case WM_PAINT:{if(pThis->m_bUpdate){pThis->Update(hwnd);pThis->m_bUpdate = false;}//return hr;break;}// In some cases of sizing, the up-right corner of the parent window region would not be properly updated// Update() again when sizing is finishedcase WM_EXITSIZEMOVE:if(pThis->m_Status & SS_VISABLE){pThis->Update(hwnd);}break;case WM_SHOWWINDOW:if(pThis->m_Status & SS_ENABLED){if(!wParam)// the window is being hidden{::ShowWindow(pThis->m_hWnd, SW_HIDE);pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);}else if(!(pThis->m_Status & SS_PARENTVISIBLE)){//pThis->Update(hwnd);pThis->m_bUpdate = true;::ShowWindow(pThis->m_hWnd, SW_SHOWNA);pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;}}break;case WM_DESTROY:DestroyWindow(pThis->m_hWnd);// Destroy the shadowbreak;case WM_NCDESTROY:s_Shadowmap->erase(hwnd);// Remove this window and shadow from the mapbreak;}#pragma warning(disable: 4312)// temporrarily disable the type_cast warning in Win32// Call the default(original) window procedure for other messages or messages processed but not returnedreturn ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);#pragma warning(default: 4312)}void CShadowUI::Update(HWND hParent){RECT WndRect;GetWindowRect(hParent, &WndRect);int nShadWndWid;int nShadWndHei;if (m_bIsImageMode){if(m_sShadowImage.IsEmpty())return;nShadWndWid = WndRect.right - WndRect.left + m_rcShadowCorner.left + m_rcShadowCorner.right;nShadWndHei = WndRect.bottom - WndRect.top + m_rcShadowCorner.top + m_rcShadowCorner.bottom;}else{nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;}// Create the alpha blending bitmapBITMAPINFO bmi;        // bitmap headerZeroMemory(&bmi, sizeof(BITMAPINFO));bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);bmi.bmiHeader.biWidth = nShadWndWid;bmi.bmiHeader.biHeight = nShadWndHei;bmi.bmiHeader.biPlanes = 1;bmi.bmiHeader.biBitCount = 32;         // four 8-bit componentsbmi.bmiHeader.biCompression = BI_RGB;bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;BYTE *pvBits;          // pointer to DIB sectionHBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);HDC hMemDC = CreateCompatibleDC(NULL);HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);if (m_bIsImageMode){RECT rcPaint = {0, 0, nShadWndWid, nShadWndHei};const TImageInfo* data = m_pManager->GetImageEx((LPCTSTR)m_sShadowImage, NULL, 0);if( !data ) return;    RECT rcBmpPart = {0};rcBmpPart.right = data->nX;rcBmpPart.bottom = data->nY;CRenderEngine::DrawImage(hMemDC, data->hBitmap, rcPaint, rcPaint, rcBmpPart, m_rcShadowCorner, data->alphaChannel, 0xFF, true, false, false);}else{ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);MakeShadow((UINT32 *)pvBits, hParent, &WndRect);}POINT ptDst;if (m_bIsImageMode){ptDst.x = WndRect.left - m_rcShadowCorner.left;ptDst.y = WndRect.top - m_rcShadowCorner.top;}else{ptDst.x = WndRect.left + m_nxOffset - m_nSize;ptDst.y = WndRect.top + m_nyOffset - m_nSize;}POINT ptSrc = {0, 0};SIZE WndSize = {nShadWndWid, nShadWndHei};BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);BOOL bRet= ::UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC,&ptSrc, 0, &blendPixelFunction, ULW_ALPHA);_ASSERT(bRet); // something was wrong....// Delete used resourcesSelectObject(hMemDC, hOriBmp);DeleteObject(hbitmap);DeleteDC(hMemDC);}void CShadowUI::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent){// The shadow algorithm:// Get the region of parent window,// Apply morphologic erosion to shrink it into the size (ShadowWndSize - Sharpness)// Apply modified (with blur effect) morphologic dilation to make the blurred border// The algorithm is optimized by assuming parent window is just "one piece" and without "wholes" on it// Get the region of parent window,HRGN hParentRgn = CreateRectRgn(0, 0, 0, 0);GetWindowRgn(hParent, hParentRgn);// Determine the Start and end point of each horizontal scan lineSIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};// Extra 2 lines (set to be empty) in ptAnchors are used in dilationint nAnchors = max(szParent.cy, szShadow.cy);// # of anchor points paresint (*ptAnchors)[2] = new int[nAnchors + 2][2];int (*ptAnchorsOri)[2] = new int[szParent.cy][2];// anchor points, will not modify during erosionptAnchors[0][0] = szParent.cx;ptAnchors[0][1] = 0;ptAnchors[nAnchors + 1][0] = szParent.cx;ptAnchors[nAnchors + 1][1] = 0;if(m_nSize > 0){// Put the parent window anchors at the centerfor(int i = 0; i < m_nSize; i++){ptAnchors[i + 1][0] = szParent.cx;ptAnchors[i + 1][1] = 0;ptAnchors[szShadow.cy - i][0] = szParent.cx;ptAnchors[szShadow.cy - i][1] = 0;}ptAnchors += m_nSize;}for(int i = 0; i < szParent.cy; i++){// find start pointint j;for(j = 0; j < szParent.cx; j++){if(PtInRegion(hParentRgn, j, i)){ptAnchors[i + 1][0] = j + m_nSize;ptAnchorsOri[i][0] = j;break;}}if(j >= szParent.cx)// Start point not found{ptAnchors[i + 1][0] = szParent.cx;ptAnchorsOri[i][1] = 0;ptAnchors[i + 1][0] = szParent.cx;ptAnchorsOri[i][1] = 0;}else{// find end pointfor(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--){if(PtInRegion(hParentRgn, j, i)){ptAnchors[i + 1][1] = j + 1 + m_nSize;ptAnchorsOri[i][1] = j + 1;break;}}}}if(m_nSize > 0)ptAnchors -= m_nSize;// Restore pos of ptAnchors for erosionint (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2];// Store the result of erosion// First and last line should be emptyptAnchorsTmp[0][0] = szParent.cx;ptAnchorsTmp[0][1] = 0;ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;ptAnchorsTmp[nAnchors + 1][1] = 0;int nEroTimes = 0;// morphologic erosionfor(int i = 0; i < m_nSharpness - m_nSize; i++){nEroTimes++;//ptAnchorsTmp[1][0] = szParent.cx;//ptAnchorsTmp[1][1] = 0;//ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;//ptAnchorsTmp[szParent.cy + 1][1] = 0;for(int j = 1; j < nAnchors + 1; j++){ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;}// Exchange ptAnchors and ptAnchorsTmp;int (*ptAnchorsXange)[2] = ptAnchorsTmp;ptAnchorsTmp = ptAnchors;ptAnchors = ptAnchorsXange;}// morphologic dilationptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1;// now coordinates in ptAnchors are same as in shadow window// Generate the kernelint nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];UINT32 *pKernelIter = pKernel;for(int i = 0; i <= 2 * nKernelSize; i++){for(int j = 0; j <= 2 * nKernelSize; j++){double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));if(dLength < nCenterSize)*pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);else if(dLength <= nKernelSize){UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));*pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);}else*pKernelIter = 0;//TRACE("%d ", *pKernelIter >> 24);pKernelIter ++;}//TRACE("\n");}// Generate blurred borderfor(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++){int j;if(ptAnchors[i][0] < ptAnchors[i][1]){// Start of linefor(j = ptAnchors[i][0];j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]);j++){for(int k = 0; k <= 2 * nKernelSize; k++){UINT32 *pPixel = pShadBits +(szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);for(int l = 0; l <= 2 * nKernelSize; l++){if(*pPixel < *pKernelPixel)*pPixel = *pKernelPixel;pPixel++;pKernelPixel++;}}}// for() start of line// End of linefor(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1);j < ptAnchors[i][1];j++){for(int k = 0; k <= 2 * nKernelSize; k++){UINT32 *pPixel = pShadBits +(szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);for(int l = 0; l <= 2 * nKernelSize; l++){if(*pPixel < *pKernelPixel)*pPixel = *pKernelPixel;pPixel++;pKernelPixel++;}}}// for() end of line}}// for() Generate blurred border// Erase unwanted parts and complement missingUINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);for(int i = min(nKernelSize, max(m_nSize - m_nyOffset, 0));i < max(szShadow.cy - nKernelSize, min(szParent.cy + m_nSize - m_nyOffset, szParent.cy + 2 * m_nSize));i++){UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy)// Line is not covered by parent window{for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++){*(pLine + j) = clCenter;}}else{for(int j = ptAnchors[i][0];j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]);j++)*(pLine + j) = clCenter;for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, 0);j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, szShadow.cx);j++)*(pLine + j) = 0;for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]);j < ptAnchors[i][1];j++)*(pLine + j) = clCenter;}}// Delete used resourcesdelete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);delete[] ptAnchorsTmp;delete[] ptAnchorsOri;delete[] pKernel;DeleteObject(hParentRgn);}void CShadowUI::ShowShadow(bool bShow){m_bIsShowShadow = bShow;}bool CShadowUI::IsShowShadow() const{return m_bIsShowShadow;}bool CShadowUI::SetSize(int NewSize){if(NewSize > 20 || NewSize < -20)return false;m_nSize = (signed char)NewSize;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetSharpness(unsigned int NewSharpness){if(NewSharpness > 20)return false;m_nSharpness = (unsigned char)NewSharpness;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetDarkness(unsigned int NewDarkness){if(NewDarkness > 255)return false;m_nDarkness = (unsigned char)NewDarkness;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetPosition(int NewXOffset, int NewYOffset){if(NewXOffset > 20 || NewXOffset < -20 ||NewYOffset > 20 || NewYOffset < -20)return false;m_nxOffset = (signed char)NewXOffset;m_nyOffset = (signed char)NewYOffset;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetColor(COLORREF NewColor){m_Color = NewColor;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetImage(LPCTSTR szImage){if (szImage == NULL)return false;m_bIsImageMode = true;m_sShadowImage = szImage;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}bool CShadowUI::SetShadowCorner(RECT rcCorner){if (rcCorner.left < 0 || rcCorner.top < 0 || rcCorner.right < 0 || rcCorner.bottom < 0)return false;m_rcShadowCorner = rcCorner;if(m_hWnd != NULL && (SS_VISABLE & m_Status))Update(GetParent(m_hWnd));return true;}} //namespace DuiLib


总结:


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


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

0 0
原创粉丝点击