VC++界面編程之--陰影窗口的實現詳解


轉載:http://blog.csdn.net/rmxming/article/details/11661365

 

對於我們這些控件狂來說,窗口陰影也是一個必不可少的實現需求。雖說其沒多大用,但對於增加窗口立體感來說,那是挺有幫助的。

我實現了一個類似於360界面的陰影效果,其可以支持正常窗口,也支持半透明窗口。

陰影窗口對於正常窗口和半透明窗口,有區別么?且讓我慢慢寫來:)

陰影窗口的實現原理,簡單來講:就是在主窗口創建時,創建一個子窗口,吸附於主窗口的底部。然后在子窗口上做一個帶半透明陰影效果的描繪。

以下代碼是陰影窗口在父窗口的創建代碼,是不是很簡單?

[html]  view plain  copy
 
  1. LRESULT OnInitDialog(UINT /*uMsg*/, WPARAM /*wParam*/, LPARAM /*lParam*/, BOOL& /*bHandled*/)  
  2. {  
  3.     m_Shadow.Create(m_hWnd);  
  4.     m_Shadow.SetShadowSize(8);  
  5.   
  6.     return TRUE;  
  7. }  

下面是陰影窗口實現步驟:

1. 在陰影窗口創建時,只設定陰影窗口的樣式為WS_VISIBLE,我們這里不能用WS_CHILD,否則陰影窗口就跑到主窗口里面去了。

[cpp]  view plain  copy
 
  1. // Create shadow window.  
  2. HWND Create(const HWND wndParent)  
  3. {  
  4.     ATLASSERT( ::IsWindow(wndParent) );  
  5.     m_hParentWnd = wndParent;  
  6.     CRect rc(1, 1, 1, 1);  
  7.     return CWindowImpl<CThemedShadowWnd, CWindow, CControlWinTraits>::Create(0, rc, NULL, WS_VISIBLE, NULL);  
  8. }  


2. 在陰影窗口執行WM_CREATE消息時,修改其樣式為WS_EX_LAYERED | WS_EX_TRANSPARENT,注意這兩個樣式都要要。WS_EX_TRANSPARENT是讓窗口無法接收點擊消息,你總不想你的窗口陰影可以被用戶點擊且激活吧:)

[cpp]  view plain  copy
 
  1. SetWindowLong(GWL_EXSTYLE, GetWindowLong(GWL_EXSTYLE) | WS_EX_LAYERED | WS_EX_TRANSPARENT);  
  2. ModifyStyleEx(WS_EX_TOPMOST, WS_EX_NOACTIVATE);  

3. 與此同時,陰影窗口注冊父窗口的消息處理回調函數,此舉是為了獲取父窗口的移動、重繪和隱藏等重要消息。因為陰影窗口要跟隨着父窗口的狀態改變而改變。

 

[cpp]  view plain  copy
 
  1. // Set parent window original processing.  
  2. m_OriParentProc = ::GetWindowLong(m_hParentWnd, GWL_WNDPROC);  
  3. ::SetWindowLong(m_hParentWnd, GWL_WNDPROC, (LONG)ParentProc);  

回調函數要做的事情很簡單,吸附於父窗口之下,像個小尾巴一樣:

 

[cpp]  view plain  copy
 
  1. // Get parent message.  
  2. static LRESULT CALLBACK ParentProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)  
  3. {  
  4.     // Find the shadow window pointer via parent window handle.  
  5.     ATLASSERT( m_szShadowWindows.find(hwnd) != m_szShadowWindows.end() );  
  6.     CThemedShadowWnd *pThis = m_szShadowWindows[hwnd];  
  7.     WNDPROC pDefProc        = (WNDPROC)pThis->m_OriParentProc;  
  8.   
  9.     switch(uMsg)  
  10.     {  
  11.     case WM_ERASEBKGND:  
  12.     case WM_PAINT:  
  13.     case WM_MOVE:  
  14.     case WM_ACTIVATE:  
  15.     case WM_NCACTIVATE:  
  16.         {  
  17.             if (::IsWindowVisible(hwnd))   
  18.             {   
  19.                 pThis->AdjustWindowPos();   
  20.             }  
  21.             break;  
  22.         }  
  23.     case WM_DESTROY:  
  24.         {  
  25.             // Destroy the shadow window.  
  26.             pThis->DestroyWindow();    
  27.             break;  
  28.         }  
  29.     case WM_NCDESTROY:  
  30.         {  
  31.             // Remove shadow window from map.  
  32.             m_szShadowWindows.erase(hwnd);    
  33.             break;  
  34.         }  
  35.     case WM_SHOWWINDOW:  
  36.         {  
  37.             // the window is being hidden  
  38.             if (!wParam)      
  39.             {  
  40.                 pThis->ShowWindow(SW_HIDE);  
  41.             }  
  42.             else  
  43.             {  
  44.                 pThis->ShowWindow(SW_SHOW);  
  45.             }  
  46.             break;  
  47.         }  
  48.     default:  
  49.         {  
  50.             break;  
  51.         }  
  52.     }  
  53.   
  54.     return pDefProc(hwnd, uMsg, wParam, lParam);  
  55. }  

好了,窗口消息機制處理完了,就要處理陰影畫法了,我這里用的是GDI+的畫法,如果有童鞋覺得效果不夠好,可以嘗試多改改參數配置,以達到理想效果:

 

[cpp]  view plain  copy
 
  1. // Create shadow brush.  
  2. PathGradientBrush brShadow(m_ShadowPath.m_pPath);  
  3. Color clrShadow[3] = {Color::Transparent, Color(255, 0, 0, 0), Color(255, 0, 0, 0)};  
  4. int nCount = 3;  
  5.   
  6. REAL szPos[3] = {0.0F, 0.05F, 1.0F};  
  7. brShadow.SetInterpolationColors(clrShadow, szPos, nCount);  
  8.   
  9. // Draw shadow.  
  10. rcShadow.Width  = rcShadow.Width - m_nShadowSize - m_nBlankArea;  
  11. rcShadow.Height = rcShadow.Height - m_nShadowSize - m_nBlankArea;  
  12. graphics.ExcludeClip(rcShadow);  
  13. graphics.FillPath(&brShadow, m_ShadowPath.m_pPath);  

 

注意我這里排除了一部分的陰影部分,那是為透明窗口制作的,排除的效果圖如下,陰影窗口只顯示在矩形的右下角,而其他地方是透明的。

 


如果我不排除一部分陰影區域,那么透明的窗口效果將變得很難看,如下圖,透明背景被陰影遮蓋了,這顯然不符合美學的要求。

如果你的窗口的角是橢圓的,你可能還需要增寬陰影的顯示區域,那么可以用如下函數進行陰影的寬度增長:

 

[cpp]  view plain  copy
 
  1. // Set blank area right position.  
  2. void SetRightOffsetArea(const int nRightPos)  
  3. {  
  4.     m_nBlankArea = nRightPos;  
  5.     if (nRightPos < 0)  
  6.     {  
  7.         m_nBlankArea = 1;  
  8.     }  
  9. }  


陰影窗口免費實例代碼下載:http://download.csdn.net/detail/renstarone/6267677

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM