MFC模拟360悬浮窗加速球窗口

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


1,目标


实现类似360悬浮窗口这样的效果,当窗口在屏幕边缘时,鼠标移开,就自动向边缘隐藏,鼠标放上去,就又平滑显示出来。


正常状态:

MFC模拟360悬浮窗加速球窗口_第1张图片

边缘自动隐藏:



2,原理


首先是实现圆角或椭圆这种不规则形状的窗口,可以参考另一篇文章:

MFC实现不规则窗口

 然后需要给没有标题栏的窗口增加拖拽移动的功能,这个就是自己手动发送一个消息,使windows认为鼠标在标题条上

对于窗口的移动显示隐藏,使用了定时器。

其中有一些做判断的函数,如判断在窗口在屏幕某个边缘,判断鼠标是否在窗口内部等。


3,实现


①新建MFC对话框程序Test360.去掉默认控件和属性中的边框。参考上面所说的文章实现一个带圆角及背景图片的窗口。


由于这里还是截图然后用PS简单选择了个范围,所以还有毛边,若是有美工原图或PS仔细些,是没问题的。


②给Dlg类CTest360Dlg添加一条消息响应OnLButtonDown,在其中传送WM_NCLBUTTONDOWN消息,达到拖动效果。

[cpp]  view plain copy
  1. void CTest360Dlg::OnLButtonDown(UINT nFlags, CPoint point)  
  2. {  
  3.     CDialog::OnLButtonDown(nFlags, point);  
  4.   
  5.     // 实现拖动窗口  
  6.     // 发送WM_NCLBUTTONDOWN消息  
  7.     // 使Windows认为鼠标在标题条上  
  8.     // 或SendMessage(WM_SYSCOMMAND,SC_MOVE | HTCAPTION,0);     
  9.     PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x, point.y));   
  10. }  

③添加几个判断窗口是否在屏幕边缘的函数:

[cpp]  view plain copy
  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. }  

④判断鼠标是否在窗口内。

[cpp]  view plain copy
  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. }  
⑤定义一个定时器,
[cpp]  view plain copy
  1. #define TIMER_MOVE 1  
在CTest360Dlg::OnInitDialog()中启动:

[cpp]  view plain copy
  1. BOOL CTest360Dlg::OnInitDialog()  
  2. {  
  3.     CDialog::OnInitDialog();  
  4.   
  5.     // 设置此对话框的图标。当应用程序主窗口不是对话框时,框架将自动  
  6.     //  执行此操作  
  7.     SetIcon(m_hIcon, TRUE);         // 设置大图标  
  8.     SetIcon(m_hIcon, FALSE);        // 设置小图标  
  9.   
  10.   
  11.     //设置窗口形状  
  12.     SetRegion(GetDC(),IDB_BITMAP_360RGN,RGB(0,0,0));  
  13.   
  14.     //初始时居中  
  15.     CenterWindow();  
  16.   
  17.     //设置定时器,处理悬浮窗的显隐移动  
  18.     SetTimer(TIMER_MOVE,10,NULL);  
  19.   
  20.     return TRUE;   
  21. }  

处理如下:

[cpp]  view plain copy
  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.       
  33.     CDialog::OnTimer(nIDEvent);  
  34. }  

其中GetKeyState先强行过滤掉鼠标按下,让这种情况不移动。避免刚拖动窗口到屏幕边缘时鼠标还没松开就直接开始移动了。

3个Move函数,是真正按像素移动窗口的地方,包括来回(出屏幕和进屏幕)。原理是一样的,看明白一个就OK了。

[cpp]  view plain copy
  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.         //窗口向左移动一像素,如果快隐藏(留20像素)就不移了  
  64.         if (rc.left<= 20 - width)  
  65.         {  
  66.             rc.left = 20 - width;  
  67.         }  
  68.         else  
  69.         {  
  70.             rc.left--;  
  71.         }  
  72.         rc.right = rc.left + width;  
  73.         MoveWindow(rc);  
  74.     }  
  75. }  
  76. void CTest360Dlg::MoveRight()  
  77. {  
  78.     CRect rc;  
  79.     GetWindowRect(rc);  
  80.     int sysWidth = GetSystemMetrics(SM_CXSCREEN);  
  81.     //鼠标在窗口内则窗口左移,显示出来  
  82.     if(MouseInWnd())  
  83.     {  
  84.         int width = rc.Width();  
  85.         if (rc.left<= sysWidth - width)  
  86.         {  
  87.             rc.left = sysWidth - width;  
  88.         }  
  89.         else  
  90.         {  
  91.             rc.left--;  
  92.         }  
  93.         rc.right = rc.left + width;  
  94.         MoveWindow(rc);  
  95.     }  
  96.     //鼠标没在窗口上,窗口就往右移出屏幕  
  97.     else  
  98.     {  
  99.         int width = rc.Width();  
  100.         //窗口向右移动一像素,如果快隐藏了(还留20像素)就不移了  
  101.         if (rc.left>= sysWidth - 20)  
  102.         {  
  103.             rc.left = sysWidth - 20;  
  104.         }  
  105.         else  
  106.         {  
  107.             rc.left++;  
  108.         }  
  109.         rc.right = rc.left + width;  
  110.         MoveWindow(rc);  
  111.     }  
  112.   
  113. }  
对MoveUp做说明:

当Timer中判断到窗口在屏幕上边缘时,进入MoveUp,如果此时鼠标进入窗口内,窗口就往下方移动直到完全显示;如果鼠标离开窗口,那么窗口会立即往上隐藏,直到留下一小截。 360官方软件现在是换了个半圆形的窗口“趴”在屏幕边上。这里主要是模拟触发移动的效果。


4,效果

几张截图

左侧:MFC模拟360悬浮窗加速球窗口_第2张图片

上侧:

右侧:MFC模拟360悬浮窗加速球窗口_第3张图片


5,源码


MFC模拟360悬浮窗加速球Test360_VS2008工程.rar

你可能感兴趣的:(MFC模拟360悬浮窗加速球窗口)