如何实现窗体的阴影环绕效果

2025-04-30 10:58:22
推荐回答(1个)
回答1:

  本节我们继续学习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);
}


  

  


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;
}