本节我们继续学习UpdateLayeredWindow这个API, 通过它我们来实现一个阴影效果的窗体(像Window7窗体效果).
思路: 1. 创建二个层窗体, 一个作为控件窗件,另一个做阴影效果窗体;
2. 在第一个窗体实现各种控件创建以及相关逻辑处理,此窗体设为全透明;
3. 将第二个窗体重叠并保持重叠第一个窗体(即大小,位置,移动或改变大小都保持一致),此窗体选入一张边沿带有阴影效果通道图(BMP, PNG)通过UpdateLayeredWindow函数年
来实现效果;
4. 截取第一个窗体中控件的图并与第二个窗体叠加,因为UpdateLayeredWindow之后的窗体有穿透能力这样更好触及到被完成透明的第一个窗体上;
声明: 此方法源于Codeproject上一个中国程序员的文章
一. 代码演示
1. 在主窗体WM_NCCREATE中调用_ShadowWnd函数, 通过此函数修改主窗体的两个属性 -- 1. 替换窗体过程函数(用于截获主窗体的消息); 2. 修改主窗体为层窗体
LRESULT CALLBACK _DefWndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
static const UINT IDC_BTNEXIT = 1002;
switch (nMsg)
{
case WM_NCCREATE:
{
_ShadowWnd(hWnd);
break;
}
...
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
{
static const UINT IDC_BTNEXIT = 1002;
switch (nMsg)
{
case WM_NCCREATE:
{
_ShadowWnd(hWnd);
break;
}
...
}
return ::DefWindowProc(hWnd, nMsg, wParam, lParam);
}
void _ShadowWnd(HWND hWnd)
{
LONG _OldWndProc = GetWindowLongPtr(hWnd, GWL_WNDPROC);
if (NULL != _OldWndProc)
{
SetWindowLongPtr(hWnd, GWL_WNDPROC, (LONG)_WndProc);
SetWindowLongPtr(hWnd, GWL_EXSTYLE, GetWindowLongPtr(hWnd, GWL_EXSTYLE)|WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, 0, 3, LWA_ALPHA);
}
return ;
}
2. 处理_WndProc中消息
a. 首先创建一个层窗体(阴影窗体)
b. 加载边沿带有阴影的效果图PNG(使用gdi+)将做为背影
c. 遍历主窗体中控件的DC, 将绘到背影上
d. 使用UpdateLayeredWindow将含有控件图的背影绘制到阴影窗体上
LRESULT CALLBACK _WndProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
HRESULT hResult = _DefWndProc(hWnd, nMsg, wParam, lParam);
static bool bUpdate = false;
static Image* pImage;
static HWND hShadowWnd = NULL;
switch (nMsg)
{
case WM_CREATE:
{
pImage = _LoadImage(IDB_PNG1, _T("PNG"), GetModuleHandle(NULL));
hShadowWnd = _CreateShadowWnd(hWnd);
break;
}
case WM_MOVE:
{
RECT rtWnd;
GetWindowRect(hWnd, &rtWnd);
if (NULL != hShadowWnd && IsWindow(hShadowWnd))
{
SetWindowPos(hShadowWnd, NULL, rtWnd.left, rtWnd.top, 0, 0, SWP_NOZORDER|SWP_NOSIZE);
}
break;
}
case WM_SIZE:
{
RECT rtWnd;
GetWindowRect(hWnd, &rtWnd);
if (NULL != hShadowWnd && IsWindow(hShadowWnd))
{
SetWindowPos(hShadowWnd, NULL, 0, 0, rtWnd.right - rtWnd.left, rtWnd.bottom - rtWnd.top, SWP_NOZORDER|SWP_NOMOVE);
}
break;
}
case WM_PAINT:
case WM_CAPTURECHANGED:
case WM_CTLCOLOREDIT:
case WM_CTLCOLORBTN:
case WM_CTLCOLORSTATIC:
case WM_CTLCOLORMSGBOX:
case WM_CTLCOLORDLG:
case WM_CTLCOLORLISTBOX:
case WM_CTLCOLORSCROLLBAR:
{
if (NULL != pImage)
{
_BlendRefresh(hShadowWnd, hWnd, pImage, 200);
}
break;
}
case WM_DESTROY:
{
if (NULL != hShadowWnd && IsWindow(hShadowWnd))
{
DestroyWindow(hShadowWnd);
}
break;
}
}
return hResult;
}
二、效果
备注: 本例中演示阴影窗体的实现,其中一些细节还要优化和实现