转载请说明原出处,谢谢: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. 支持向量机SVM 初识

    虽然已经学习了神经网络和深度学习并在几个项目之中加以运用了,但在斯坦福公开课上听吴恩达老师说他(在当时)更喜欢使用SVM,而很少使用神经网络来解决问题,因此来学习一下SVM的种种. 先解释一些概念吧: ...

  2. 定制自己的动画 View 控件(Canvas 使用)

    定制自己的动画 View 控件(Canvas 使用) 如果要定义自己的 View 控件,则需要新建一个类继承 android.view.View.然后在 onDraw 中写自己需要实现的方式. 这里定 ...

  3. java调试器

    javac.exe是编译.java文件 java.exe是执行编译好的.class文件 javadoc.exe是生成Java说明文档 jdb.exe是Java调试器 javaprof.exe是剖析工具 ...

  4. 2018软工实践—Alpha冲刺(5)

    队名 火箭少男100 组长博客 林燊大哥 作业博客 Alpha 冲鸭鸭鸭鸭鸭! 成员冲刺阶段情况 林燊(组长) 过去两天完成了哪些任务 协调各成员之间的工作 协助测试的进行 测试项目运行的服务器环境 ...

  5. 基于DPDK的高效数据包捕获技术分析与应用

    被NFV的论文折磨了两天,今天上午看了两篇DPDK的综述. 传统的包捕获机制 1. BPF 两个组成部分:转发部分和过滤部分. 转发部分负责从链路层提取数据包并转发给过滤部分. 过滤部分根据过滤规则, ...

  6. phpdisk 盲注 &前台任意用户登录

    代码审核 文件 plugins\phpdisk_client\passport.php 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 $str ...

  7. css新增UI方案

    一.文本新增样式 opacity 不透明度 h1{ margin: 100px auto; opacity: 0.5; } </style> </head> <body& ...

  8. QThread安全的结束线程

    版权声明:若无来源注明,Techie亮博客文章均为原创. 转载请以链接形式标明本文标题和地址: 本文标题:QThread安全的结束线程     本文地址:http://techieliang.com/ ...

  9. (转)ActiveMQ的重连机制

    花了一天的时间,终于搞明白了我的疑问. failover://(tcp://localhost:6168)?randomize=false&initialReconnectDelay=100& ...

  10. C#和Java在多态情况下对成员访问的比较

    本文简单比较一下两种语言在里氏替换原则下,父类引用变量访问成员时的访问结果: 如果有两个类,如Person与Student,后者继承了前者,而且子类与父类有重名成员,当Person p = new S ...