原作者:http://blog.163.com/toplcx@yeah/blog/static/92667383201021932360/
原理: 创建一个单独的非模态对话框,并将其置顶
1、 在解决方案中添加对话框资源 ID:IDD_FLOAT 属性 Border设为none,Title 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_EXSTYLE, WS_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悬浮窗口这样的效果,当窗口在屏幕边缘时,鼠标移开,就自动向边缘隐藏,鼠标放上去,就又平滑显示出来。
正常状态:
边缘自动隐藏:
首先是实现圆角或椭圆这种不规则形状的窗口,可以参考另一篇文章:
MFC实现不规则窗口
然后需要给没有标题栏的窗口增加拖拽移动的功能,这个就是自己手动发送一个消息,使windows认为鼠标在标题条上
对于窗口的移动显示隐藏,使用了定时器。
其中有一些做判断的函数,如判断在窗口在屏幕某个边缘,判断鼠标是否在窗口内部等。
①新建MFC对话框程序Test360.去掉默认控件和属性中的边框。参考上面所说的文章实现一个带圆角及背景图片的窗口。
由于这里还是截图然后用PS简单选择了个范围,所以还有毛边,若是有美工原图或PS仔细些,是没问题的。
②给Dlg类CTest360Dlg添加一条消息响应OnLButtonDown,在其中传送WM_NCLBUTTONDOWN消息,达到拖动效果。
3个Move函数,是真正按像素移动窗口的地方,包括来回(出屏幕和进屏幕)。原理是一样的,看明白一个就OK了。
当Timer中判断到窗口在屏幕上边缘时,进入MoveUp,如果此时鼠标进入窗口内,窗口就往下方移动直到完全显示;如果鼠标离开窗口,那么窗口会立即往上隐藏,直到留下一小截。 360官方软件现在是换了个半圆形的窗口“趴”在屏幕边上。这里主要是模拟触发移动的效果。
几张截图
MFC模拟360悬浮窗加速球Test360_VS2008工程.rar