打开APP
userphoto
未登录

开通VIP,畅享免费电子书等14项超值服

开通VIP
duilib创建的窗体添加边框阴影效果

在使用duilib过程中,发现很多人提到关于创建窗体边框阴影效果的问题,查阅了下相关资料,找到如下代码,记录如下:

WndShadow.h头文件

1#pragma once
2 
3#include "map"
4 
5class CWndShadow
6{
7public:
8    CWndShadow(void);
9public:
10    virtual ~CWndShadow(void);
11 
12protected:
13 
14    // Instance handle, used to register window class and create window
15    static HINSTANCE s_hInstance;
16 
17    // Parent HWND and CWndShadow object pares, in order to find CWndShadow in ParentProc()
18    static std::map<HWND, CWndShadow *> s_Shadowmap;
19 
20    //
21    typedef BOOL (WINAPI *pfnUpdateLayeredWindow)(HWND hWnd, HDC hdcDst, POINT *pptDst,
22        SIZE *psize, HDC hdcSrc, POINT *pptSrc, COLORREF crKey,
23        BLENDFUNCTION *pblend, DWORD dwFlags);
24    static pfnUpdateLayeredWindow s_UpdateLayeredWindow;
25 
26    HWND m_hWnd;
27 
28    LONG m_OriParentProc;   // Original WndProc of parent window
29 
30    enum ShadowStatus
31    {
32        SS_ENABLED = 1, // Shadow is enabled, if not, the following one is always false
33        SS_VISABLE = 1 << 1,  // Shadow window is visible
34        SS_PARENTVISIBLE = 1<< 2  // Parent window is visible, if not, the above one is always false
35    };
36    BYTE m_Status;
37 
38    unsigned char m_nDarkness;  // Darkness, transparency of blurred area
39    unsigned char m_nSharpness; // Sharpness, width of blurred border of shadow window
40    signed char m_nSize;    // Shadow window size, relative to parent window size
41 
42    // The X and Y offsets of shadow window,
43    // relative to the parent window, at center of both windows (not top-left corner), signed
44    signed char m_nxOffset;
45    signed char m_nyOffset;
46 
47    // Restore last parent window size, used to determine the update strategy when parent window is resized
48    LPARAM m_WndSize;
49 
50    // Set this to true if the shadow should not be update until next WM_PAINT is received
51    bool m_bUpdate;
52 
53    COLORREF m_Color;   // Color of shadow
54 
55public:
56    static bool Initialize(HINSTANCE hInstance);
57    void Create(HWND hParentWnd);
58 
59    bool SetSize(int NewSize = 0);
60    bool SetSharpness(unsigned int NewSharpness = 5);
61    bool SetDarkness(unsigned int NewDarkness = 200);
62    bool SetPosition(int NewXOffset = 5, int NewYOffset = 5);
63    bool SetColor(COLORREF NewColor = 0);
64 
65protected:
66    //static LRESULT CALLBACK WndProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
67    static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
68 
69    // Redraw, resize and move the shadow
70    // called when window resized or shadow properties changed, but not only moved without resizing
71    void Update(HWND hParent);
72 
73    // Fill in the shadow window alpha blend bitmap with shadow image pixels
74    void MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent);
75 
76    // Helper to calculate the alpha-premultiled value for a pixel
77    inline DWORD PreMultiply(COLORREF cl, unsigned char nAlpha)
78    {
79        // It's strange that the byte order of RGB in 32b BMP is reverse to in COLORREF
80        return (GetRValue(cl) * (DWORD)nAlpha / 255) << 16 |
81            (GetGValue(cl) * (DWORD)nAlpha / 255) << 8 |
82            (GetBValue(cl) * (DWORD)nAlpha / 255);
83    }
84};

WndShadow.cpp源文件

1#include "StdAfx.h"
2#include "WndShadow.h"
3#include "math.h"
4#include "crtdbg.h"
5 
6// Some extra work to make this work in VC++ 6.0
7 
8// walk around the for iterator scope bug of VC++6.0
9#ifdef _MSC_VER
10#if _MSC_VER == 1200
11#define for if(false);else for
12#endif
13#endif
14 
15// Some definitions for VC++ 6.0 without newest SDK
16#ifndef WS_EX_LAYERED
17#define WS_EX_LAYERED 0x00080000
18#endif
19 
20#ifndef AC_SRC_ALPHA
21#define AC_SRC_ALPHA 0x01
22#endif
23 
24#ifndef ULW_ALPHA
25#define ULW_ALPHA 0x00000002
26#endif
27 
28CWndShadow::pfnUpdateLayeredWindow CWndShadow::s_UpdateLayeredWindow = NULL;
29 
30const TCHAR *strWndClassName = _T("PerryShadowWnd");
31 
32HINSTANCE CWndShadow::s_hInstance = (HINSTANCE)INVALID_HANDLE_VALUE;
33 
34std::map<HWND, CWndShadow *> CWndShadow::s_Shadowmap;
35 
36CWndShadow::CWndShadow(void)
37: m_hWnd((HWND)INVALID_HANDLE_VALUE)
38, m_OriParentProc(NULL)
39, m_nDarkness(150)
40, m_nSharpness(5)
41, m_nSize(0)
42, m_nxOffset(5)
43, m_nyOffset(5)
44, m_Color(RGB(0, 0, 0))
45, m_WndSize(0)
46, m_bUpdate(false)
47{
48}
49 
50CWndShadow::~CWndShadow(void)
51{
52}
53 
54bool CWndShadow::Initialize(HINSTANCE hInstance)
55{
56    // Should not initiate more than once
57    if (NULL != s_UpdateLayeredWindow)
58        return false;
59 
60    HMODULE hUser32 = GetModuleHandle(_T("USER32.DLL"));
61    s_UpdateLayeredWindow =
62        (pfnUpdateLayeredWindow)GetProcAddress(hUser32,
63        "UpdateLayeredWindow");
64 
65    // If the import did not succeed, make sure your app can handle it!
66    if (NULL == s_UpdateLayeredWindow)
67        return false;
68 
69    // Store the instance handle
70    s_hInstance = hInstance;
71 
72    // Register window class for shadow window
73    WNDCLASSEX wcex;
74 
75    memset(&wcex, 0, sizeof(wcex));
76 
77    wcex.cbSize = sizeof(WNDCLASSEX);
78    wcex.style          = CS_HREDRAW | CS_VREDRAW;
79    wcex.lpfnWndProc    = DefWindowProc;
80    wcex.cbClsExtra     = 0;
81    wcex.cbWndExtra     = 0;
82    wcex.hInstance      = hInstance;
83    wcex.hIcon          = NULL;
84    wcex.hCursor        = LoadCursor(NULL, IDC_ARROW);
85    wcex.hbrBackground  = (HBRUSH)(COLOR_WINDOW+1);
86    wcex.lpszMenuName   = NULL;
87    wcex.lpszClassName  = strWndClassName;
88    wcex.hIconSm        = NULL;
89 
90    RegisterClassEx(&wcex);
91 
92    return true;
93}
94 
95void CWndShadow::Create(HWND hParentWnd)
96{
97    // Do nothing if the system does not support layered windows
98    if(NULL == s_UpdateLayeredWindow)
99        return;
100 
101    // Already initialized
102    _ASSERT(s_hInstance != INVALID_HANDLE_VALUE);
103 
104    // Add parent window - shadow pair to the map
105    _ASSERT(s_Shadowmap.find(hParentWnd) == s_Shadowmap.end()); // Only one shadow for each window
106    s_Shadowmap[hParentWnd] = this;
107 
108    // Create the shadow window
109    m_hWnd = CreateWindowEx(WS_EX_LAYERED | WS_EX_TRANSPARENT, strWndClassName, NULL,
110        /*WS_VISIBLE | */WS_CAPTION | WS_POPUPWINDOW,
111        CW_USEDEFAULT, 0, 0, 0, hParentWnd, NULL, s_hInstance, NULL);
112 
113    // Determine the initial show state of shadow according to parent window's state
114    LONG lParentStyle = GetWindowLong(hParentWnd, GWL_STYLE);
115    if(!(WS_VISIBLE & lParentStyle))    // Parent invisible
116        m_Status = SS_ENABLED;
117    else if((WS_MAXIMIZE | WS_MINIMIZE) & lParentStyle) // Parent visible but does not need shadow
118        m_Status = SS_ENABLED | SS_PARENTVISIBLE;
119    else    // Show the shadow
120    {
121        m_Status = SS_ENABLED | SS_VISABLE | SS_PARENTVISIBLE;
122        ::ShowWindow(m_hWnd, SW_SHOWNA);
123        Update(hParentWnd);
124    }
125 
126    // Replace the original WndProc of parent window to steal messages
127    m_OriParentProc = GetWindowLong(hParentWnd, GWL_WNDPROC);
128 
129#pragma warning(disable: 4311)  // temporrarily disable the type_cast warning in Win32
130    SetWindowLong(hParentWnd, GWL_WNDPROC, (LONG)ParentProc);
131#pragma warning(default: 4311)
132 
133}
134 
135LRESULT CALLBACK CWndShadow::ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
136{
137    _ASSERT(s_Shadowmap.find(hwnd) != s_Shadowmap.end());   // Shadow must have been attached
138 
139    CWndShadow *pThis = s_Shadowmap[hwnd];
140 
141    switch(uMsg)
142    {
143    case WM_MOVE:
144        if(pThis->m_Status & SS_VISABLE)
145        {
146            RECT WndRect;
147            GetWindowRect(hwnd, &WndRect);
148            SetWindowPos(pThis->m_hWnd, 0,
149                WndRect.left + pThis->m_nxOffset - pThis->m_nSize, WndRect.top + pThis->m_nyOffset - pThis->m_nSize,
150                0, 0, SWP_NOSIZE | SWP_NOACTIVATE);
151        }
152        break;
153 
154    case WM_SIZE:
155        if(pThis->m_Status & SS_ENABLED)
156        {
157            if(SIZE_MAXIMIZED == wParam || SIZE_MINIMIZED == wParam)
158            {
159                ::ShowWindow(pThis->m_hWnd, SW_HIDE);
160                pThis->m_Status &= ~SS_VISABLE;
161            }
162            else if(pThis->m_Status & SS_PARENTVISIBLE)  // Parent maybe resized even if invisible
163            {
164                // Awful! It seems that if the window size was not decreased
165                // the window region would never be updated until WM_PAINT was sent.
166                // So do not Update() until next WM_PAINT is received in this case
167                if(LOWORD(lParam) > LOWORD(pThis->m_WndSize) || HIWORD(lParam) > HIWORD(pThis->m_WndSize))
168                    pThis->m_bUpdate = true;
169                else
170                    pThis->Update(hwnd);
171                if(!(pThis->m_Status & SS_VISABLE))
172                {
173                    ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);
174                    pThis->m_Status |= SS_VISABLE;
175                }
176            }
177            pThis->m_WndSize = lParam;
178        }
179        break;
180 
181    case WM_PAINT:
182        {
183            if(pThis->m_bUpdate)
184            {
185                pThis->Update(hwnd);
186                pThis->m_bUpdate = false;
187            }
188            //return hr;
189            break;
190        }
191 
192        // In some cases of sizing, the up-right corner of the parent window region would not be properly updated
193        // Update() again when sizing is finished
194    case WM_EXITSIZEMOVE:
195        if(pThis->m_Status & SS_VISABLE)
196        {
197            pThis->Update(hwnd);
198        }
199        break;
200 
201    case WM_SHOWWINDOW:
202        if(pThis->m_Status & SS_ENABLED)
203        {
204            if(!wParam) // the window is being hidden
205            {
206                ::ShowWindow(pThis->m_hWnd, SW_HIDE);
207                pThis->m_Status &= ~(SS_VISABLE | SS_PARENTVISIBLE);
208            }
209            else if(!(pThis->m_Status & SS_PARENTVISIBLE))
210            {
211                //pThis->Update(hwnd);
212                pThis->m_bUpdate = true;
213                ::ShowWindow(pThis->m_hWnd, SW_SHOWNA);
214                pThis->m_Status |= SS_VISABLE | SS_PARENTVISIBLE;
215            }
216        }
217        break;
218 
219    case WM_DESTROY:
220        DestroyWindow(pThis->m_hWnd);    // Destroy the shadow
221        break;
222 
223    case WM_NCDESTROY:
224        s_Shadowmap.erase(hwnd);    // Remove this window and shadow from the map
225        break;
226 
227    }
228 
229#pragma warning(disable: 4312)  // temporrarily disable the type_cast warning in Win32
230    // Call the default(original) window procedure for other messages or messages processed but not returned
231    return ((WNDPROC)pThis->m_OriParentProc)(hwnd, uMsg, wParam, lParam);
232#pragma warning(default: 4312)
233 
234}
235 
236void CWndShadow::Update(HWND hParent)
237{
238    //int ShadSize = 5;
239    //int Multi = 100 / ShadSize;
240 
241    RECT WndRect;
242    GetWindowRect(hParent, &WndRect);
243    int nShadWndWid = WndRect.right - WndRect.left + m_nSize * 2;
244    int nShadWndHei = WndRect.bottom - WndRect.top + m_nSize * 2;
245 
246    // Create the alpha blending bitmap
247    BITMAPINFO bmi;        // bitmap header
248 
249    ZeroMemory(&bmi, sizeof(BITMAPINFO));
250    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
251    bmi.bmiHeader.biWidth = nShadWndWid;
252    bmi.bmiHeader.biHeight = nShadWndHei;
253    bmi.bmiHeader.biPlanes = 1;
254    bmi.bmiHeader.biBitCount = 32;         // four 8-bit components
255    bmi.bmiHeader.biCompression = BI_RGB;
256    bmi.bmiHeader.biSizeImage = nShadWndWid * nShadWndHei * 4;
257 
258    BYTE *pvBits;          // pointer to DIB section
259    HBITMAP hbitmap = CreateDIBSection(NULL, &bmi, DIB_RGB_COLORS, (void **)&pvBits, NULL, 0);
260 
261    ZeroMemory(pvBits, bmi.bmiHeader.biSizeImage);
262    MakeShadow((UINT32 *)pvBits, hParent, &WndRect);
263 
264    HDC hMemDC = CreateCompatibleDC(NULL);
265    HBITMAP hOriBmp = (HBITMAP)SelectObject(hMemDC, hbitmap);
266 
267    POINT ptDst = {WndRect.left + m_nxOffset - m_nSize, WndRect.top + m_nyOffset - m_nSize};
268    POINT ptSrc = {0, 0};
269    SIZE WndSize = {nShadWndWid, nShadWndHei};
270    BLENDFUNCTION blendPixelFunction= { AC_SRC_OVER, 0, 255, AC_SRC_ALPHA };
271 
272    MoveWindow(m_hWnd, ptDst.x, ptDst.y, nShadWndWid, nShadWndHei, FALSE);
273 
274    BOOL bRet= s_UpdateLayeredWindow(m_hWnd, NULL, &ptDst, &WndSize, hMemDC,
275        &ptSrc, 0, &blendPixelFunction, ULW_ALPHA);
276 
277    _ASSERT(bRet); // something was wrong....
278 
279    // Delete used resources
280    SelectObject(hMemDC, hOriBmp);
281    DeleteObject(hbitmap);
282    DeleteDC(hMemDC);
283 
284}
285 
286void CWndShadow::MakeShadow(UINT32 *pShadBits, HWND hParent, RECT *rcParent)
287{
288    // The shadow algorithm:
289    // Get the region of parent window,
290    // Apply morphologic erosion to shrink it into the size (ShadowWndSize - Sharpness)
291    // Apply modified (with blur effect) morphologic dilation to make the blurred border
292    // The algorithm is optimized by assuming parent window is just "one piece" and without "wholes" on it
293 
294    // Get the region of parent window,
295    HRGN hParentRgn = CreateRectRgn(0, 0, 0, 0);
296    GetWindowRgn(hParent, hParentRgn);
297 
298    // Determine the Start and end point of each horizontal scan line
299    SIZE szParent = {rcParent->right - rcParent->left, rcParent->bottom - rcParent->top};
300    SIZE szShadow = {szParent.cx + 2 * m_nSize, szParent.cy + 2 * m_nSize};
301    // Extra 2 lines (set to be empty) in ptAnchors are used in dilation
302    int nAnchors = max(szParent.cy, szShadow.cy);   // # of anchor points pares
303    int (*ptAnchors)[2] = new int[nAnchors + 2][2];
304    int (*ptAnchorsOri)[2] = new int[szParent.cy][2];   // anchor points, will not modify during erosion
305    ptAnchors[0][0] = szParent.cx;
306    ptAnchors[0][1] = 0;
307    ptAnchors[nAnchors + 1][0] = szParent.cx;
308    ptAnchors[nAnchors + 1][1] = 0;
309    if(m_nSize > 0)
310    {
311        // Put the parent window anchors at the center
312        for(int i = 0; i < m_nSize; i++)
313        {
314            ptAnchors[i + 1][0] = szParent.cx;
315            ptAnchors[i + 1][1] = 0;
316            ptAnchors[szShadow.cy - i][0] = szParent.cx;
317            ptAnchors[szShadow.cy - i][1] = 0;
318        }
319        ptAnchors += m_nSize;
320    }
321    for(int i = 0; i < szParent.cy; i++)
322    {
323        // find start point
324        int j;
325        for(j = 0; j < szParent.cx; j++)
326        {
327            if(PtInRegion(hParentRgn, j, i))
328            {
329                ptAnchors[i + 1][0] = j + m_nSize;
330                ptAnchorsOri[i][0] = j;
331                break;
332            }
333        }
334 
335        if(j >= szParent.cx) // Start point not found
336        {
337            ptAnchors[i + 1][0] = szParent.cx;
338            ptAnchorsOri[i][1] = 0;
339            ptAnchors[i + 1][0] = szParent.cx;
340            ptAnchorsOri[i][1] = 0;
341        }
342        else
343        {
344            // find end point
345            for(j = szParent.cx - 1; j >= ptAnchors[i + 1][0]; j--)
346            {
347                if(PtInRegion(hParentRgn, j, i))
348                {
349                    ptAnchors[i + 1][1] = j + 1 + m_nSize;
350                    ptAnchorsOri[i][1] = j + 1;
351                    break;
352                }
353            }
354        }
355    }
356 
357    if(m_nSize > 0)
358        ptAnchors -= m_nSize;   // Restore pos of ptAnchors for erosion
359    int (*ptAnchorsTmp)[2] = new int[nAnchors + 2][2];  // Store the result of erosion
360    // First and last line should be empty
361    ptAnchorsTmp[0][0] = szParent.cx;
362    ptAnchorsTmp[0][1] = 0;
363    ptAnchorsTmp[nAnchors + 1][0] = szParent.cx;
364    ptAnchorsTmp[nAnchors + 1][1] = 0;
365    int nEroTimes = 0;
366    // morphologic erosion
367    for(int i = 0; i < m_nSharpness - m_nSize; i++)
368    {
369        nEroTimes++;
370        //ptAnchorsTmp[1][0] = szParent.cx;
371        //ptAnchorsTmp[1][1] = 0;
372        //ptAnchorsTmp[szParent.cy + 1][0] = szParent.cx;
373        //ptAnchorsTmp[szParent.cy + 1][1] = 0;
374        for(int j = 1; j < nAnchors + 1; j++)
375        {
376            ptAnchorsTmp[j][0] = max(ptAnchors[j - 1][0], max(ptAnchors[j][0], ptAnchors[j + 1][0])) + 1;
377            ptAnchorsTmp[j][1] = min(ptAnchors[j - 1][1], min(ptAnchors[j][1], ptAnchors[j + 1][1])) - 1;
378        }
379        // Exchange ptAnchors and ptAnchorsTmp;
380        int (*ptAnchorsXange)[2] = ptAnchorsTmp;
381        ptAnchorsTmp = ptAnchors;
382        ptAnchors = ptAnchorsXange;
383    }
384 
385    // morphologic dilation
386    ptAnchors += (m_nSize < 0 ? -m_nSize : 0) + 1;   // now coordinates in ptAnchors are same as in shadow window
387    // Generate the kernel
388    int nKernelSize = m_nSize > m_nSharpness ? m_nSize : m_nSharpness;
389    int nCenterSize = m_nSize > m_nSharpness ? (m_nSize - m_nSharpness) : 0;
390    UINT32 *pKernel = new UINT32[(2 * nKernelSize + 1) * (2 * nKernelSize + 1)];
391    UINT32 *pKernelIter = pKernel;
392    for(int i = 0; i <= 2 * nKernelSize; i++)
393    {
394        for(int j = 0; j <= 2 * nKernelSize; j++)
395        {
396            double dLength = sqrt((i - nKernelSize) * (i - nKernelSize) + (j - nKernelSize) * (double)(j - nKernelSize));
397            if(dLength < nCenterSize)
398                *pKernelIter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
399            else if(dLength <= nKernelSize)
400            {
401                UINT32 nFactor = ((UINT32)((1 - (dLength - nCenterSize) / (m_nSharpness + 1)) * m_nDarkness));
402                *pKernelIter = nFactor << 24 | PreMultiply(m_Color, nFactor);
403            }
404            else
405                *pKernelIter = 0;
406            //TRACE("%d ", *pKernelIter >> 24);
407            pKernelIter ++;
408        }
409        //TRACE("\n");
410    }
411    // Generate blurred border
412    for(int i = nKernelSize; i < szShadow.cy - nKernelSize; i++)
413    {
414        int j;
415        if(ptAnchors[i][0] < ptAnchors[i][1])
416        {
417 
418            // Start of line
419            for(j = ptAnchors[i][0];
420                j < min(max(ptAnchors[i - 1][0], ptAnchors[i + 1][0]) + 1, ptAnchors[i][1]);
421                j++)
422            {
423                for(int k = 0; k <= 2 * nKernelSize; k++)
424                {
425                    UINT32 *pPixel = pShadBits +
426                        (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
427                    UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
428                    for(int l = 0; l <= 2 * nKernelSize; l++)
429                    {
430                        if(*pPixel < *pKernelPixel)
431                            *pPixel = *pKernelPixel;
432                        pPixel++;
433                        pKernelPixel++;
434                    }
435                }
436            }   // for() start of line
437 
438            // End of line
439            for(j = max(j, min(ptAnchors[i - 1][1], ptAnchors[i + 1][1]) - 1);
440                j < ptAnchors[i][1];
441                j++)
442            {
443                for(int k = 0; k <= 2 * nKernelSize; k++)
444                {
445                    UINT32 *pPixel = pShadBits +
446                        (szShadow.cy - i - 1 + nKernelSize - k) * szShadow.cx + j - nKernelSize;
447                    UINT32 *pKernelPixel = pKernel + k * (2 * nKernelSize + 1);
448                    for(int l = 0; l <= 2 * nKernelSize; l++)
449                    {
450                        if(*pPixel < *pKernelPixel)
451                            *pPixel = *pKernelPixel;
452                        pPixel++;
453                        pKernelPixel++;
454                    }
455                }
456            }   // for() end of line
457 
458        }
459    }   // for() Generate blurred border
460 
461    // Erase unwanted parts and complement missing
462    UINT32 clCenter = m_nDarkness << 24 | PreMultiply(m_Color, m_nDarkness);
463    for(int i = min(nKernelSize, max(m_nSize - m_nyOffset, 0));
464        i < max(szShadow.cy - nKernelSize, min(szParent.cy + m_nSize - m_nyOffset, szParent.cy + 2 * m_nSize));
465        i++)
466    {
467        UINT32 *pLine = pShadBits + (szShadow.cy - i - 1) * szShadow.cx;
468        if(i - m_nSize + m_nyOffset < 0 || i - m_nSize + m_nyOffset >= szParent.cy)   // Line is not covered by parent window
469        {
470            for(int j = ptAnchors[i][0]; j < ptAnchors[i][1]; j++)
471            {
472                *(pLine + j) = clCenter;
473            }
474        }
475        else
476        {
477            for(int j = ptAnchors[i][0];
478                j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, ptAnchors[i][1]);
479                j++)
480                *(pLine + j) = clCenter;
481            for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][0] + m_nSize - m_nxOffset, 0);
482                j < min(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, szShadow.cx);
483                j++)
484                *(pLine + j) = 0;
485            for(int j = max(ptAnchorsOri[i - m_nSize + m_nyOffset][1] + m_nSize - m_nxOffset, ptAnchors[i][0]);
486                j < ptAnchors[i][1];
487                j++)
488                *(pLine + j) = clCenter;
489        }
490    }
491 
492    // Delete used resources
493    delete[] (ptAnchors - (m_nSize < 0 ? -m_nSize : 0) - 1);
494    delete[] ptAnchorsTmp;
495    delete[] ptAnchorsOri;
496    delete[] pKernel;
497    DeleteObject(hParentRgn);
498}
499 
500bool CWndShadow::SetSize(int NewSize)
501{
502    if(NewSize > 20 || NewSize < -20)
503        return false;
504 
505    m_nSize = (signed char)NewSize;
506    if(SS_VISABLE & m_Status)
507        Update(GetParent(m_hWnd));
508    return true;
509}
510 
511bool CWndShadow::SetSharpness(unsigned int NewSharpness)
512{
513    if(NewSharpness > 20)
514        return false;
515 
516    m_nSharpness = (unsigned char)NewSharpness;
517    if(SS_VISABLE & m_Status)
518        Update(GetParent(m_hWnd));
519    return true;
520}
521 
522bool CWndShadow::SetDarkness(unsigned int NewDarkness)
523{
524    if(NewDarkness > 255)
525        return false;
526 
527    m_nDarkness = (unsigned char)NewDarkness;
528    if(SS_VISABLE & m_Status)
529        Update(GetParent(m_hWnd));
530    return true;
531}
532 
533bool CWndShadow::SetPosition(int NewXOffset, int NewYOffset)
534{
535    if(NewXOffset > 20 || NewXOffset < -20 ||
536        NewYOffset > 20 || NewYOffset < -20)
537        return false;
538 
539    m_nxOffset = (signed char)NewXOffset;
540    m_nyOffset = (signed char)NewYOffset;
541    if(SS_VISABLE & m_Status)
542        Update(GetParent(m_hWnd));
543    return true;
544}
545 
546bool CWndShadow::SetColor(COLORREF NewColor)
547{
548    m_Color = NewColor;
549    if(SS_VISABLE & m_Status)
550        Update(GetParent(m_hWnd));
551    return true;
552}

Duilib中使用方法:

1. 在要添加阴影效果的窗体类中包含WndShadow的头文件,并创建对应类型的成员变量m_WndShadow。

2. 在WinMain处添加初始化

1// Initiation of the shadow
2CWndShadow::Initialize(hInstance);

3. 窗体OnCreate中设置

1LRESULT OnCreate(UINT uMsg, WPARAM wParam, LPARAM lParam, BOOL& bHandled)
2{
3    LONG styleValue = ::GetWindowLong(*this, GWL_STYLE);
4    styleValue &= ~WS_CAPTION;
5    ::SetWindowLong(*this, GWL_STYLE, styleValue | WS_CLIPSIBLINGS | WS_CLIPCHILDREN);
6    m_WndShadow.Create(m_hWnd);
7    m_WndShadow.SetSize(4);
8    m_WndShadow.SetPosition(0, 0);
9 
10    //blablabla....
11    return 0;
12}

实例效果(此处以Duilib中的360Demo为例):

1. 未添加窗体边框阴影效果图(点击图片可查看大图)

 

2. 添加窗体边框阴影效果图(点击图片可查看大图)

说明:此处为了更清除的看到窗体边框阴影效果,我将调用的地方原来的m_WndShadow.SetSize(4);改为

了m_WndShadow.SetSize(15);正常情况下,Size设置为4的效果即可。

 

【WndShadow文件下载http://yun.baidu.com/s/1mZjmY

本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请点击举报
打开APP,阅读全文并永久保存 查看更多类似文章
猜你喜欢
类似文章
也说说Thunk - 桃之夭夭,灼灼其华.
gh0st源码分析与远控的编写(二)
深入剖析WTL
请教个小问题, 跨线程传窗口对象指针,程序崩溃
Thunk and its uses
bmp转tiff
更多类似文章 >>
生活服务
热点新闻
分享 收藏 导长图 关注 下载文章
绑定账号成功
后续可登录账号畅享VIP特权!
如果VIP功能使用有故障,
可点击这里联系客服!

联系客服