MFC模擬360懸浮窗加速球視窗
阿新 • • 發佈:2019-01-04
http://blog.csdn.net/dpsying/article/details/17264339
1,目標
實現類似360懸浮視窗這樣的效果,當視窗在螢幕邊緣時,滑鼠移開,就自動向邊緣隱藏,滑鼠放上去,就又平滑顯示出來。
正常狀態:
邊緣自動隱藏:
2,原理
首先是實現圓角或橢圓這種不規則形狀的視窗,可以參考另一篇文章:
然後需要給沒有標題欄的視窗增加拖拽移動的功能,這個就是自己手動傳送一個訊息,使windows認為滑鼠在標題條上
對於視窗的移動顯示隱藏,使用了定時器。
其中有一些做判斷的函式,如判斷在視窗在螢幕某個邊緣,判斷滑鼠是否在視窗內部等。
3,實現
①新建MFC對話方塊程式Test360.去掉預設控制元件和屬性中的邊框。參考上面所說的文章實現一個帶圓角及背景圖片的視窗。
由於這裡還是截圖然後用PS簡單選擇了個範圍,所以還有毛邊,若是有美工原圖或PS仔細些,是沒問題的。
②給Dlg類CTest360Dlg新增一條訊息響應OnLButtonDown,在其中傳送WM_NCLBUTTONDOWN訊息,達到拖動效果。
- void CTest360Dlg::OnLButtonDown(UINT nFlags, CPoint point)
- {
-
CDialog::OnLButtonDown(nFlags, point);
- // 實現拖動視窗
- // 傳送WM_NCLBUTTONDOWN訊息
- // 使Windows認為滑鼠在標題條上
- // 或SendMessage(WM_SYSCOMMAND,SC_MOVE | HTCAPTION,0);
- PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x, point.y));
- }
③新增幾個判斷視窗是否在螢幕邊緣的函式:
- //是否靠近螢幕左邊緣
- BOOL CTest360Dlg::NearLeftBorder()
- {
- CRect rc;
-
GetWindowRect(rc);
- //視窗左邊界在螢幕左邊界20畫素內都算“靠近”
- if (rc.left < 20)
- {
- return TRUE;
- }
- return FALSE;
- }
- //是否靠近螢幕上邊緣
- BOOL CTest360Dlg::NearUpBorder()
- {
- CRect rc;
- GetWindowRect(rc);
- if(rc.top<20)
- {
- return TRUE;
- }
- return FALSE;
- }
- //是否靠近右邊緣
- BOOL CTest360Dlg::NearRightBorder()
- {
- CRect rc;
- GetWindowRect(rc);
- int nWidth = GetSystemMetrics(SM_CXSCREEN);
- if (rc.left>nWidth - rc.Width())
- {
- return TRUE;
- }
- return FALSE;
- }
④判斷滑鼠是否在視窗內。
- BOOL CTest360Dlg::MouseInWnd()
- {
- CRect rc;
- GetWindowRect(rc);
- POINT pt;
- GetCursorPos(&pt);
- if (PtInRect(&rc,pt))
- {
- return TRUE;
- }
- return FALSE;
- }
- #define TIMER_MOVE 1
- BOOL CTest360Dlg::OnInitDialog()
- {
- CDialog::OnInitDialog();
- // 設定此對話方塊的圖示。當應用程式主視窗不是對話方塊時,框架將自動
- // 執行此操作
- SetIcon(m_hIcon, TRUE); // 設定大圖示
- SetIcon(m_hIcon, FALSE); // 設定小圖示
- //設定視窗形狀
- SetRegion(GetDC(),IDB_BITMAP_360RGN,RGB(0,0,0));
- //初始時居中
- CenterWindow();
- //設定定時器,處理懸浮窗的顯隱移動
- SetTimer(TIMER_MOVE,10,NULL);
- return TRUE;
- }
處理如下:
- void CTest360Dlg::OnTimer(UINT_PTR nIDEvent)
- {
- if (nIDEvent == TIMER_MOVE)
- {
- //滑鼠按著的,就怎麼都不移動
- if (GetKeyState(VK_LBUTTON)<0)
- {
- return;
- }
- //靠近螢幕上邊緣
- if (NearUpBorder())
- {
- //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向下平移顯示,滑鼠離開就向上平移隱藏)
- MoveUp();
- return;
- }
- //靠近螢幕左邊緣
- if (NearLeftBorder())
- {
- //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向右平移顯示,滑鼠離開就向左平移隱藏)
- MoveLeft();
- return;
- }
- //靠近螢幕右邊緣
- if (NearRightBorder())
- {
- //根據滑鼠動作進行視窗的移動(滑鼠進入區域就向左平移顯示,滑鼠離開就向右平移隱藏)
- MoveRight();
- return;
- }
- }
- CDialog::OnTimer(nIDEvent);
- }
其中GetKeyState先強行過濾掉滑鼠按下,讓這種情況不移動。避免剛拖動視窗到螢幕邊緣時滑鼠還沒鬆開就直接開始移動了。
3個Move函式,是真正按畫素移動視窗的地方,包括來回(出螢幕和進螢幕)。原理是一樣的,看明白一個就OK了。
- void CTest360Dlg::MoveUp()
- {
- CRect rc;
- GetWindowRect(rc);
- //滑鼠進入則下移,顯示出來
- if(MouseInWnd())
- {
- int height = rc.Height();
- if (rc.top>=0)
- {
- rc.top = 0;
- }
- else
- {
- rc.top++;
- }
- rc.bottom = rc.top + height;
- MoveWindow(rc);
- }
- //滑鼠在別處,視窗就往上移出螢幕
- else
- {
- int height = rc.Height();
- //視窗向上移動一畫素,如果快隱藏(露20)就不移了
- if (rc.top<= 20 - height)
- {
- rc.top = 20 - height;
- ShowWindow(SW_HIDE);
- m_upDlg->m_Test360Dlg = this;
- m_upDlg->DoModal();
- }
- else
- {
- rc.top--;
- }
- rc.bottom = rc.top + height;
- MoveWindow(rc);
- }
- }
- void CTest360Dlg::MoveLeft()
- {
- CRect rc;
- GetWindowRect(rc);
- //滑鼠進入則下移,顯示出來
- if(MouseInWnd())
- {
- int width = rc.Width();
- if (rc.left>=0)
- {
- rc.left = 0;
- }
- else
- {
- rc.left++;
- }
- rc.right = rc.left + width;
- MoveWindow(rc);
- }
- //滑鼠在別處,視窗就往上移出螢幕
- else
- {
- int width = rc.Width();
- //視窗向左移動一畫