转载请说明原出处,谢谢: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="shadowpositon" 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" shadowpositon="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/09
filename: UIShadow.h
author: Redrain purpose: 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 false
SS_VISABLE = 1 << 1, // Shadow window is visible
SS_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 area
unsigned char m_nSharpness; // Sharpness, width of blurred border of shadow window
signed 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), signed
signed char m_nxOffset;
signed char m_nyOffset; // Restore last parent window size, used to determine the update strategy when parent window is resized
LPARAM m_WndSize; // Set this to true if the shadow should not be update until next WM_PAINT is received
bool m_bUpdate; COLORREF m_Color; // Color of shadow // 图片阴影成员变量
CDuiString m_sShadowImage;
RECT m_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 window
WNDCLASSEX 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 state
LONG lParentStyle = GetWindowLong(hParentWnd, GWL_STYLE); // Create the shadow window
LONG 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 invisible
m_Status = SS_ENABLED;
else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
m_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 messages
m_OriParentProc = GetWindowLong(hParentWnd, GWL_WNDPROC); #pragma warning(disable: 4311) // temporrarily disable the type_cast warning in Win32
SetWindowLong(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 attached CShadowUI *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 case
if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))
pThis->m_bUpdate = true;
else
pThis->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 finished
case 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 shadow
break; case WM_NCDESTROY:
s_Shadowmap->erase(hwnd); // Remove this window and shadow from the map
break; } #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 returned
return ((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 bitmap
BITMAPINFO bmi; // bitmap header ZeroMemory(&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 components
bmi.bmiHeader.biCompression = BI_RGB;
bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4; BYTE *pvBits; // pointer to DIB section
HBITMAP 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 resources
SelectObject(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 line
SIZE 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 dilation
int nAnchors = max(szParent.cy, szShadow.cy); // # of anchor points pares
int (*ptAnchors)[2] = new int[nAnchors + 2][2];
int (*ptAnchorsOri)[2] = new int[szParent.cy][2]; // anchor points, will not modify during erosion
ptAnchors[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 center
for(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 point
int 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 point
for(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 erosion
int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2]; // Store the result of erosion
// First and last line should be empty
ptAnchorsTmp[0][0] = szParent.cx;
ptAnchorsTmp[0][1] = 0;
ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;
ptAnchorsTmp[nAnchors + 1][1] = 0;
int nEroTimes = 0;
// morphologic erosion
for(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 dilation
ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1; // now coordinates in ptAnchors are same as in shadow window
// Generate the kernel
int 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 border
for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)
{
int j;
if(ptAnchors[i][0] < ptAnchors[i][1])
{ // Start of line
for(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 line
for(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 missing
UINT32 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 resources
delete[] (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,可以下载我的库:点击打开链接

duilib 使用图片素材或者算法给窗体增加阴影(源码和demo)的更多相关文章

  1. [算法1-排序](.NET源码学习)& LINQ & Lambda

    [算法1-排序](.NET源码学习)& LINQ & Lambda 说起排序算法,在日常实际开发中我们基本不在意这些事情,有API不用不是没事找事嘛.但必要的基础还是需要了解掌握. 排 ...

  2. 基于wke封装的duilib的webkit浏览器控件,可以c++与js互交,源码及demo下载地址

    转载请说明原出处,谢谢~~ 前些日子用wke内核封装了duilib的webkit浏览器控件,好多群里朋友私聊我希望可以我公布源码,今天把这个控件的源码和使用demo公布.其实这个控件封装起来没什么难度 ...

  3. 量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python)(转)

    量化交易中VWAP/TWAP算法的基本原理和简单源码实现(C++和python) 原文地址:http://blog.csdn.net/u012234115/article/details/728300 ...

  4. 网易2017校园招聘算法题c语言实现源码

    题目: 给定一个数组,除了一个数出现1次之外,其余数都出现3次.找出出现一次的数.如:{1, 2, 1, 2, 1, 2, 7}, 找出7. 格式: 第一行输入一个数n,代表数组的长度,接下来一行输入 ...

  5. 数据挖掘Aprior算法详解及c++源码

    [算法大致描述] Aprior算法主要有两个操作,扫描数据库+统计.计算每一阶频繁项集都要扫描一次数据库并且统计出满足支持度的n阶项集. [算法主要步骤] 一.频繁一项集 算法开始第一步,通过扫描数据 ...

  6. 梯度下降优化算法综述与PyTorch实现源码剖析

    现代的机器学习系统均利用大量的数据,利用梯度下降算法或者相关的变体进行训练.传统上,最早出现的优化算法是SGD,之后又陆续出现了AdaGrad.RMSprop.ADAM等变体,那么这些算法之间又有哪些 ...

  7. 你需要知道的九大排序算法【Python实现】源码

    #coding: utf-8 #!/usr/bin/python import randomimport math #随机生成0~100之间的数值def get_andomNumber(num): l ...

  8. 【算法】Bert预训练源码阅读

    Bert预训练源码 主要代码 地址:https://github.com/google-research/bert create_pretraning_data.py:原始文件转换为训练数据格式 to ...

  9. Winform窗体设计工具源码

    源代码:QQ群616945527,博客资源

随机推荐

  1. pyqt5实现SMTP邮件发送

    # -*- coding: utf-8 -*- # Form implementation generated from reading ui file 'SMTP.ui' # # Created b ...

  2. Python 内置函数介绍

    作者博文地址:http://www.cnblogs.com/spiritman/ Python Built-in Functions

  3. Buy the Ticket HDU 1133 卡特兰数应用+Java大数

    Problem Description The "Harry Potter and the Goblet of Fire" will be on show in the next ...

  4. Split the Number(思维)

    You are given an integer x. Your task is to split the number x into exactly n strictly positive inte ...

  5. 《JavaScript》JS中的常用方法attr(),splice()

    1.jquery中用attr()方法来获取和设置元素属性,attr是attribute(属性)的缩写,在jQuery DOM操作中会经常用到attr(),attr()有4个表达式. attr(属性名) ...

  6. Alpha冲刺——第五天

    Alpha第五天 听说 031502543 周龙荣(队长) 031502615 李家鹏 031502632 伍晨薇 031502637 张柽 031502639 郑秦 1.前言 任务分配是VV.ZQ. ...

  7. Nginx 配置站点

    1-进入 配置文件夹   cd /etc/nginx/cof.d   2-创建一个一站点名称命名的配置文件   vim kestrel-syslyracom.conf   3-在.conf 文件中输入 ...

  8. Floyd算法(原理|代码实现)

    http://www.cnblogs.com/twjcnblog/archive/2011/09/07/2170306.html 正如我们所知道的,Floyd算法用于求最短路径.Floyd算法可以说是 ...

  9. SQL之case when then用法详解

    case具有两种格式.简单case函数和case搜索函数. <span style="font-size:14px;">--简单case函数 case sex when ...

  10. Hadoop HDFS环境搭建

    1,首先安装JDK,下面如果JDK出现安装错误,可以卸载 卸载 1.卸载用 bin文件安装的JDK方法: 删除/usr/java目录下的所有东西 2.卸载系统自带的jdk版本方法: 查看自带的jdk: ...