创建悬浮框

原作者:http://blog.163.com/toplcx@yeah/blog/static/92667383201021932360/

原理创建一个单独的非模态对话框,并将其置顶

1、  在解决方案中添加对话框资源 IDIDD_FLOAT 属性 Border设为noneTitle Bar设为false。为对话框模板添加基于CDialog的类CFloatDlg,为CMainFrame添加指针变量m_pFdlg

2、  CMainFrame::OnCreate()中添加

m_pFdlg = new CFloatDlg();

m_pFdlg->Create( IDD_FLOAT, NULL);//

CRect rect;

m_pFdlg->GetWindowRect( &rect );

m_pFdlg->SetWindowPos( &wndTopMost, rect.left, rect.top, rect.Width(), rect.Height(), SWP_SHOWWINDOW );//置顶显示

// GetSystemMetrics(SM_CXSCREEN)获得屏幕的宽度,此句设置悬浮窗初始屏幕位置

m_pFdlg->MoveWindow( GetSystemMetrics(SM_CXSCREEN) - 70, 70, rect.Width(), rect.Height(), TRUE )

m_pFdlg->ShowWindow(SW_SHOW); //显示对话框

m_pFdlg->UpdateWindow();

3、最后不要忘了释放释放资源

void CMainFrame::OnClose()
 {             //
销毁对话框 
             delete dlg;

CFrameWnd::OnClose(); 
 }

至此已经出现了一个非模态对话框 接下来对其进行一下初始化使其更像悬浮框

1、  隐藏悬浮窗在任务栏上的显示

CFloatDlg::OnInitDialog()开始中添加

::SetWindowLong(GetSafeHwnd(), GWL_EXSTYLEWS_EX_TOOLWINDOW); //隐藏对话框在任务栏上的显示

2、  半透明化

同上在初始化中添加

SetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE,

GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);

HINSTANCE hInst = LoadLibrary("User32.DLL");

if(hInst)

{

typedef BOOL (WINAPI *MYFUNC)(HWND,COLORREF,BYTE,DWORD);

MYFUNC fun = NULL;

//取得SetLayeredWindowAttributes函数指针

fun=(MYFUNC)GetProcAddress(hInst, "SetLayeredWindowAttributes");

if(fun)fun(this->GetSafeHwnd(),124,128,2); //2代表透明化的程度5为完全透明

FreeLibrary(hInst);

}

3、  添加图片,添加一个位图资源 直接在对话框中放置一个Picture ControL显示图片即可

4、  设置悬浮框的大小,在对话框类中响应WM_SIZE消息,SetWindowPos(NULL,0,0,40,40,SWP_NOREPOSITION);

5、  实现左击拖动悬浮窗分别响应左键按下抬起 以及鼠标移动

类添加BOOL变量 m_bLBDown,指示左键有没有按下,CPoint变量m_ptLBBegin,记录左键按下时的窗口坐标

void CFloatDlg::OnLButtonDown(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

   m_bLBDown=TRUE;

   m_ptLBBegin=point;

   CDialog::OnLButtonDown(nFlags, point);

}

void CFloatDlg::OnMouseMove(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

   if (m_bLBDown)

   {

            CPoint pt;

            ::GetCursorPos(&pt);

            MoveWindow(pt.x-m_ptLBBegin.x,pt.y-m_ptLBBegin.y,40,40);

            CDialog::OnLButtonUp(nFlags, point);

            CRect rect;

            GetWindowRect(&rect);

            ClipCursor(&rect);

   }

   CDialog::OnMouseMove(nFlags, point);

}

void CFloatDlg::OnLButtonUp(UINT nFlags, CPoint point)

{

   // TODO: 在此添加消息处理程序代码和/或调用默认值

   ClipCursor(NULL);

   m_bLBDown=FALSE;

}

6、   至于其他的消息响应 比如右击弹出菜单等,就像一般普通的对话框一样重载响应的消息即可。


仿制 360 桌面悬浮框 

1、目标


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


正常状态:


边缘自动隐藏:



2,原理


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

MFC实现不规则窗口

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

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

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


3,实现


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


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


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

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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 在CODE上查看代码片 派生到我的代码片
  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 在CODE上查看代码片 派生到我的代码片
  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 在CODE上查看代码片 派生到我的代码片
  1. #define TIMER_MOVE 1  
在CTest360Dlg::OnInitDialog()中启动:

[cpp]  view plain copy 在CODE上查看代码片 派生到我的代码片
  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 在CODE上查看代码片 派生到我的代码片
  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 在CODE上查看代码片 派生到我的代码片
  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,效果

几张截图

左侧:

上侧:

右侧:


5,源码


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


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值