悬浮窗口开放源码
上次发了一篇帖子,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 编辑 ]










学习