Windows的菜单一层一层的,有时操作起来不方便,就想自己写个工具直接调用。对迅雷的悬浮窗垂涎好久了,哈,正好趁这个机会搞一搞。在悬浮窗上用快捷菜单不是很方便吗?
在VC知识库中找到了一篇介绍悬浮窗实现的例子,很好,拿来就用,又做了些增强功能,呵呵,特此Show一下。知识库文章地址:
点这里。
要实现悬浮窗,就得弄明白悬浮窗是什么,有什么行为和作用。悬浮窗其实是一个无边框可以拖动的窗口,再有就是它上面铺满一张图,当然也可以是空白,可以设置透明度,双击可实现主窗口的显示和隐藏,右键有菜单,可以实现快捷操作;还有一点就是它在任务栏中不显示。好了,明白了原理就开始找资料动手了。
我的习惯是先攻克所有的技术点,然后再动手写程序。在资源文件中插入一个Dialog,给它添加一个类CFloatWnd。首先是无边框,这个容易,将窗口的Border设为None就可以了。无边框窗口的拖动也很容易,重写OnNcHitTest就可以了。原理就是当用户点击了窗口客户区后,把它当成标题栏来传给操作系统,这样就实现了拖动。代码如下:
- LRESULT CFloatWnd::OnNcHitTest(CPoint point)
- {
-
- LRESULT nHitTest = CDialog::OnNcHitTest(point);
-
- if (nHitTest == HTCLIENT && GetAsyncKeyState(MK_LBUTTON) < 0 )
- nHitTest = HTCAPTION;
-
- return nHitTest;
-
- }
不要认为GetAsyncKeyState没有用,这样做的目的是点击左键拖动,而点击右键则不能拖动且要弹出右键菜单。
好了,现在窗口能拖动了,但是是空白窗口,不好看。那好,加个位图,首先添加资源文件Logo.bmp,资源ID设为IDB_BITMAP_Logo,然后在窗口上放个Picture Control,Type指定为Bitmap,image设为IDB_BITMAP_Logo就可以了。至于图片位置和窗口大小就写程序控制好了。给图片添加变量m_Logo。在OnInitDialog中添加如下代码:
-
-
-
-
-
- CBitmap m_Bitmap;
- HBITMAP hBitmap = m_Logo.GetBitmap();
- ASSERT(hBitmap);
- m_Bitmap.Attach(hBitmap);
- BITMAP bmp;
- m_Bitmap.GetBitmap(&bmp);
-
- int nX = bmp.bmWidth;
- int nY = bmp.bmHeight;
- MoveWindow(0,0,nX,nY);
- m_Logo.MoveWindow(0,0,nX,nY);
- CenterWindow();
- ::SetWindowPos(m_hWnd,HWND_TOPMOST,0,0,0,0,SWP_NOMOVE | SWP_NOSIZE);
- m_Bitmap.Detach();
做完这些以后在主窗口CMainAppDlg中添加成员变量CFloatWnd m_FloatWnd; 然后在CMainAppDlg的OnInitDialog中添加如下代码,来显示我们的悬浮窗。
-
- m_FloatWnd.Create(CFloatWnd::IDD,this);
- m_FloatWnd.ShowWindow(SW_SHOW);
还有,别忘记在MainAppDlg.h 中添加这个:#include "FloatWnd.h"
好了,现在运行。感觉上挺不错了,但是双击不能显示主窗口,也没有右键菜单。嗯,继续做吧。添加成员函数afx_msg void OnShowHide(); //显示隐藏具体代码如下:
-
- void CFloatWnd::OnShowHide()
- {
- CWnd *pParent = GetParent();
- ASSERT(pParent);
- if(pParent->IsWindowVisible())
- pParent->ShowWindow(SW_HIDE);
- else
- pParent->ShowWindow(SW_SHOW);
- }
-
- void CFloatWnd::OnNcLButtonDblClk(UINT nHitTest, CPoint point)
- {
-
- OnShowHide();
- CDialog::OnNcLButtonDblClk(nHitTest, point);
- }
运行一下,双击能够显示和隐藏,效果还是不错的。下一步添加右键菜单。在资源文件里添加个新菜单,ID设为IDR_MENU_FloatWnd,然后添加两个子菜单项:1、Caption为显示/隐藏主窗口(&S) ,ID为ID_ShowHide;2、Caption为退出(&E) ,ID为ID_Exit。给CFloatWnd添加菜单成员变量:CMenu m_Right; //右键菜单在OnInitDialog中加载:
-
- m_Right.LoadMenu(IDR_MENU_FloatWnd);
-
-
- void CFloatWnd::OnRButtonUp(UINT nFlags, CPoint point)
- {
-
- CMenu *pSub = m_Right.GetSubMenu(0);
- ClientToScreen(&point);
- pSub->TrackPopupMenu(TPM_LEFTALIGN,point.x,point.y,this,NULL);
- CDialog::OnRButtonUp(nFlags, point);
- }
-
- ON_COMMAND(ID_Exit, OnExit)
- ON_COMMAND(ID_ShowHide, OnShowHide)
-
-
- void CFloatWnd::OnExit()
- {
- CWnd *pParent = GetParent();
- this->DestroyWindow();
- pParent->DestroyWindow();
- }
运行一下,效果很棒。但还没有透明度设置。
在主窗口上放一个Slider Control,给它添加变量m_Slider,最大值设为255,最小值设为0。然后重写窗口的OnHScroll事件,在事件中根据滑动条的值来设置窗口的透明度。关于窗口的透明度,在VC2005中可以直接用SetLayeredWindowAttributes来设置,在VC6中要用LoadLibrary("User32.DLL")来实现。好了,完整代码如下:
-
-
- m_Slider.SetRangeMax(255,TRUE);
- m_Slider.SetRangeMin(1,TRUE);
-
- m_Slider.SetPageSize(10);
-
- void CFloatWnd::OnUpdateTransparent(int iTransparent)
- {
- SetLayeredWindowAttributes(0,iTransparent,2);
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- }
-
-
- SetWindowLong(m_hWnd,GWL_EXSTYLE,GetWindowLong(this->GetSafeHwnd(),GWL_EXSTYLE)^0x80000);
-
- OnUpdateTransparent(255);