1. 程式人生 > >MFC模擬360懸浮窗加速球視窗

MFC模擬360懸浮窗加速球視窗

http://blog.csdn.net/dpsying/article/details/17264339

1,目標

實現類似360懸浮視窗這樣的效果,當視窗在螢幕邊緣時,滑鼠移開,就自動向邊緣隱藏,滑鼠放上去,就又平滑顯示出來。

正常狀態:


邊緣自動隱藏:


2,原理

首先是實現圓角或橢圓這種不規則形狀的視窗,可以參考另一篇文章:

 然後需要給沒有標題欄的視窗增加拖拽移動的功能,這個就是自己手動傳送一個訊息,使windows認為滑鼠在標題條上

對於視窗的移動顯示隱藏,使用了定時器。

其中有一些做判斷的函式,如判斷在視窗在螢幕某個邊緣,判斷滑鼠是否在視窗內部等。

3,實現

①新建MFC對話方塊程式Test360.去掉預設控制元件和屬性中的邊框。參考上面所說的文章實現一個帶圓角及背景圖片的視窗。


由於這裡還是截圖然後用PS簡單選擇了個範圍,所以還有毛邊,若是有美工原圖或PS仔細些,是沒問題的。

②給Dlg類CTest360Dlg新增一條訊息響應OnLButtonDown,在其中傳送WM_NCLBUTTONDOWN訊息,達到拖動效果。

  1. void CTest360Dlg::OnLButtonDown(UINT nFlags, CPoint point)  
  2. {  
  3.     CDialog::OnLButtonDown(nFlags, point);  
  4.     // 實現拖動視窗
  5.     // 傳送WM_NCLBUTTONDOWN訊息
  6.     // 使Windows認為滑鼠在標題條上
  7.     // 或SendMessage(WM_SYSCOMMAND,SC_MOVE | HTCAPTION,0);   
  8.     PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x, point.y));   
  9. }  

③新增幾個判斷視窗是否在螢幕邊緣的函式:
  1. //是否靠近螢幕左邊緣
  2. BOOL CTest360Dlg::NearLeftBorder()  
  3. {  
  4.     CRect rc;  
  5.     GetWindowRect(rc);  
  6.     //視窗左邊界在螢幕左邊界20畫素內都算“靠近”
  7.     if (rc.left < 20)  
  8.     {  
  9.         return TRUE;  
  10.     }  
  11.     return FALSE;  
  12. }  
  13. //是否靠近螢幕上邊緣
  14. BOOL CTest360Dlg::NearUpBorder()  
  15. {  
  16.     CRect rc;  
  17.     GetWindowRect(rc);  
  18.     if(rc.top<20)  
  19.     {  
  20.         return TRUE;  
  21.     }  
  22.     return FALSE;  
  23. }  
  24. //是否靠近右邊緣
  25. BOOL CTest360Dlg::NearRightBorder()  
  26. {  
  27.     CRect rc;  
  28.     GetWindowRect(rc);  
  29.     int nWidth = GetSystemMetrics(SM_CXSCREEN);  
  30.     if (rc.left>nWidth - rc.Width())  
  31.     {  
  32.         return TRUE;  
  33.     }  
  34.     return FALSE;  
  35. }  

④判斷滑鼠是否在視窗內。
  1. BOOL CTest360Dlg::MouseInWnd()  
  2. {  
  3.     CRect rc;  
  4.     GetWindowRect(rc);  
  5.     POINT pt;  
  6.     GetCursorPos(&pt);  
  7.     if (PtInRect(&rc,pt))  
  8.     {  
  9.         return TRUE;  
  10.     }  
  11.     return FALSE;  
  12. }  
⑤定義一個定時器,
  1. #define TIMER_MOVE 1
在CTest360Dlg::OnInitDialog()中啟動:
  1. BOOL CTest360Dlg::OnInitDialog()  
  2. {  
  3.     CDialog::OnInitDialog();  
  4.     // 設定此對話方塊的圖示。當應用程式主視窗不是對話方塊時,框架將自動
  5.     //  執行此操作
  6.     SetIcon(m_hIcon, TRUE);         // 設定大圖示
  7.     SetIcon(m_hIcon, FALSE);        // 設定小圖示
  8.     //設定視窗形狀
  9.     SetRegion(GetDC(),IDB_BITMAP_360RGN,RGB(0,0,0));  
  10.     //初始時居中
  11.     CenterWindow();  
  12.     //設定定時器,處理懸浮窗的顯隱移動
  13.     SetTimer(TIMER_MOVE,10,NULL);  
  14.     return TRUE;   
  15. }  

處理如下:
  1. void CTest360Dlg::OnTimer(UINT_PTR nIDEvent)  
  2. {  
  3.     if (nIDEvent == TIMER_MOVE)  
  4.     {  
  5.         //滑鼠按著的,就怎麼都不移動
  6.         if (GetKeyState(VK_LBUTTON)<0)  
  7.         {  
  8.             return;  
  9.         }  
  10.         //靠近螢幕上邊緣
  11.         if (NearUpBorder())  
  12.         {  
  13.             //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向下平移顯示,滑鼠離開就向上平移隱藏)
  14.             MoveUp();  
  15.             return;  
  16.         }  
  17.         //靠近螢幕左邊緣
  18.         if (NearLeftBorder())  
  19.         {  
  20.             //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向右平移顯示,滑鼠離開就向左平移隱藏)
  21.             MoveLeft();  
  22.             return;  
  23.         }  
  24.         //靠近螢幕右邊緣
  25.         if (NearRightBorder())  
  26.         {  
  27.             //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向左平移顯示,滑鼠離開就向右平移隱藏)
  28.             MoveRight();  
  29.             return;  
  30.         }  
  31.     }  
  32.     CDialog::OnTimer(nIDEvent);  
  33. }  

其中GetKeyState先強行過濾掉滑鼠按下,讓這種情況不移動。避免剛拖動視窗到螢幕邊緣時滑鼠還沒鬆開就直接開始移動了。

3個Move函式,是真正按畫素移動視窗的地方,包括來回(出螢幕和進螢幕)。原理是一樣的,看明白一個就OK了。

  1. void CTest360Dlg::MoveUp()  
  2. {  
  3.     CRect rc;  
  4.     GetWindowRect(rc);  
  5.     //滑鼠進入則下移,顯示出來
  6.     if(MouseInWnd())  
  7.     {  
  8.         int height = rc.Height();  
  9.         if (rc.top>=0)  
  10.         {  
  11.             rc.top = 0;  
  12.         }  
  13.         else
  14.         {  
  15.             rc.top++;  
  16.         }  
  17.         rc.bottom = rc.top + height;  
  18.         MoveWindow(rc);  
  19.     }  
  20.     //滑鼠在別處,視窗就往上移出螢幕
  21.     else
  22.     {  
  23.         int height = rc.Height();  
  24.         //視窗向上移動一畫素,如果快隱藏(露20)就不移了
  25.         if (rc.top<= 20 - height)  
  26.         {  
  27.             rc.top = 20 - height;  
  28.             ShowWindow(SW_HIDE);  
  29.             m_upDlg->m_Test360Dlg = this;  
  30.             m_upDlg->DoModal();  
  31.         }  
  32.         else
  33.         {  
  34.             rc.top--;  
  35.         }  
  36.         rc.bottom = rc.top + height;  
  37.         MoveWindow(rc);  
  38.     }  
  39. }  
  40. void CTest360Dlg::MoveLeft()  
  41. {  
  42.     CRect rc;  
  43.     GetWindowRect(rc);  
  44.     //滑鼠進入則下移,顯示出來
  45.     if(MouseInWnd())  
  46.     {  
  47.         int width = rc.Width();  
  48.         if (rc.left>=0)  
  49.         {  
  50.             rc.left = 0;  
  51.         }  
  52.         else
  53.         {  
  54.             rc.left++;  
  55.         }  
  56.         rc.right = rc.left + width;  
  57.         MoveWindow(rc);  
  58.     }  
  59.     //滑鼠在別處,視窗就往上移出螢幕
  60.     else
  61.     {  
  62.         int width = rc.Width();  
  63.         //視窗向左移動一畫