悬浮窗口开放源码
上次发了一篇帖子,https://bbs.bccn.net/thread-390247-1-1.html,里面没有提供源码,今天再开一篇帖子,分享一下源码!如果写的有问题,还忘大家指点!
对于MFC中有个悬浮窗口的类:CDockablePane,感兴趣的朋友可以自己上网查找资料研究学习!
下面讲解一下我自己实现的悬浮窗口类,通过一个对话框来实现的,对话框模式选择为POPUP类型,因为我这个没有标题栏,所以选择为none,ID为IDD_POPUP,
实现功能:初始化为一个小窗口,通过CStatic控件将图片显示在该窗口上,避免了窗口大小变化时处理WM_PAINT消息,这样小窗口展现的就是一张小图片了,当鼠标移入到小窗口时,处理WM_MOUSEMOVE消息,在该消息的处理函数中添加监控鼠标离开窗口事件,调用函数_TrackMouseEvent函数,关于这个函数的用法可查阅msdn,该函数发送WM_MOUSELEAVE消息,在该消息的处理函数中判断此时的鼠标位置是否处于窗口的客户区,如果不在的话,则窗口变小。
代码如下:
程序代码:
#ifndef CPOPWINDOW_H #define CPOPWINDOW_H class CPopWindow : public CDialog { DECLARE_DYNAMIC(CPopWindow) public: CPopWindow(CWnd* pParent = NULL); virtual ~CPopWindow(); enum { IDD = IDD_POPUP }; protected: virtual void DoDataExchange(CDataExchange* pDX); public: void SetSmallRect(CRect &Crect); void SetBigRect(CRect &Crect); void SetImage(CRect &Crect, LPCTSTR lpszPath); public: afx_msg void OnMouseMove(UINT nFlags, CPoint point); LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); DECLARE_MESSAGE_MAP() public: CStatic m_Static; CRect m_rcBig; CRect m_rcSmall; }; #endif //CPOPWINDOW_H
程序代码:
#define IDC_MY_STATIC 2000 IMPLEMENT_DYNAMIC(CPopWindow, CDialog) CPopWindow::CPopWindow(CWnd* pParent /*=NULL*/) : CDialog(CDlgInfo::IDD, pParent) { } CPopWindow::~CPopWindow() { } void CPopWindow::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CPopWindow, CDialog) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) END_MESSAGE_MAP() BOOL CPopWindow::SetImage(CRect &Crect, LPCTSTR lpszPath) { HBITMAP hBmp=(HBITMAP)::LoadImage( 0, lpszPath, IMAGE_BITMAP, Crect.Width(), Crect.Height(), LR_LOADFROMFILE ); m_Static.Create(NULL, WS_CHILD | WS_VISIBLE | SS_BITMAP, Crect, this, IDC_MY_STATIC); m_Static.SetBitmap(hBmp); } void CPopWindow::SetSmallRect(CRect &Crect) { m_rcSmall = Crect; MoveWindow(&m_rcSmall); } void CPopWindow::SetBigRect(CRect &Crect) { m_rcBig = Crect; } void CPopWindow::OnMouseMove(UINT nFlags, CPoint point) { TRACKMOUSEEVENT tme; tme.cbSize=sizeof(TRACKMOUSEEVENT); //监控鼠标离开 tme.dwFlags = TME_LEAVE; tme.hwndTrack=this->m_hWnd; if(::_TrackMouseEvent(&tme)) { m_Static.ShowWindow(SW_HIDE); MoveWindow(&m_rcBig); } } LRESULT CPopWindow::OnMouseLeave(WPARAM wParam, LPARAM lParam) { CPoint pt; GetCursorPos(&pt); //获取相对于屏幕的坐标 if(!m_rcBig.PtInRect(pt)) { m_Static.ShowWindow(SW_SHOW); MoveWindow(&m_rcSmall); } return TRUE; }注意:因为该对话框模式属于POPUP所以SetBigRect和SetSmallRect函数传入的Crect参数应该是相对于屏幕坐标,而SetImage传入的Crect参数是相对于客户区坐标
上述程序执行后,效果很好,应该达到了我们想要的结果吧,可是不然,如果创建一个子控件完全覆盖对话框,会导致对话框无法接收到WM_MOUSEMOVE消息,当然也就无法实现最后的效果,开始的时候我没有想到这一点,在我的第一篇帖子中TonyDeng提到了这一点,当时没有考虑,实际却遇到这样的问题,不得不说TonyDeng比我高明,所以为了避免这样的情况,我采用鼠标钩子,把所以发往消息队列中的WM_MOUSEMOVE消息截获到,自己先处理一下,然后再发给窗口,
代码如下:
程序代码:
#ifndef CPOPWINDOW_H #define CPOPWINDOW_H class CPopWindow : public CDialog { DECLARE_DYNAMIC(CPopWindow) public: CPopWindow(CWnd* pParent = NULL); virtual ~CPopWindow(); enum { IDD = IDD_POPUP }; protected: virtual void DoDataExchange(CDataExchange* pDX); public: void SetSmallRect(CRect &Crect); void SetBigRect(CRect &Crect); void SetImage(CRect &Crect, LPCTSTR lpszPath); DECLARE_MESSAGE_MAP() public: CStatic m_Static; CRect m_rcBig; CRect m_rcSmall; };
程序代码:
#define IDC_MY_STATIC 2000 HHOOK g_hHook; //鼠标钩子句柄 CDlgInfo *g_PopWindow; LRESULT CALLBACK MouseProc(int nCode, WPARAM wParam, LPARAM lParam) { if(wParam == WM_MOUSEMOVE) { POINT pt; pt = ((MOUSEHOOKSTRUCT *)lParam)->pt; CRect Crect; g_PopWindow->GetClientRect(&Crect); g_PopWindow->ClientToScreen(&Crect); if(!Crect.PtInRect(pt)) { g_PopWindow->m_Static.ShowWindow(SW_SHOW); g_PopWindow->MoveWindow(&g_PopWindow->m_rcSmall); } else { g_PopWindow->m_Static.ShowWindow(SW_HIDE); g_PopWindow->MoveWindow(&g_PopWindow->m_rcBig); } } return CallNextHookEx(g_hHook, nCode, wParam, lParam); } IMPLEMENT_DYNAMIC(CPopWindow, CDialog) CPopWindow::CPopWindow(CWnd* pParent /*=NULL*/) : CDialog(CDlgInfo::IDD, pParent) { g_PopWindow = this; g_hHook = ::SetWindowsHookEx(WH_MOUSE, MouseProc, 0, GetCurrentThreadId()); } CPopWindow::~CPopWindow() { if(g_hHook) { ::UnhookWindowsHookEx(g_hHook); } } void CPopWindow::DoDataExchange(CDataExchange* pDX) { CDialog::DoDataExchange(pDX); } BEGIN_MESSAGE_MAP(CPopWindow, CDialog) END_MESSAGE_MAP() BOOL CPopWindow::SetImage(CRect &Crect, LPCTSTR lpszPath) { HBITMAP hBmp=(HBITMAP)::LoadImage( 0, lpszPath, IMAGE_BITMAP, Crect.Width(), Crect.Height(), LR_LOADFROMFILE ); m_Static.Create(NULL, WS_CHILD | WS_VISIBLE | SS_BITMAP, Crect, this, IDC_MY_STATIC); m_Static.SetBitmap(hBmp); } void CPopWindow::SetSmallRect(CRect &Crect) { m_rcSmall = Crect; MoveWindow(&m_rcSmall); } void CPopWindow::SetBigRect(CRect &Crect) { m_rcBig = Crect; }
这样就避免了上述的问题了!
说明:CStatic控件的大小最好与小窗口的大小一样,小窗口看起来就好像是一张图片了!
如果大家还有更好的方法欢迎一起交流学习!
QQ群:234174291
[ 本帖最后由 我菜119 于 2012-12-13 23:12 编辑 ]