目标
实现像迅雷那样炫酷的悬浮窗。
计划&方案
首先第一步要实现一个悬浮窗,窗体无边框,能够随意拖动。
对于一个窗体来说,只有我们把鼠标放到标题栏中才进入到拖拽模式。
由于是无边框的窗体,默认是不能够移动的。我们尝试用两种办法使其跟随鼠标移动。一个是用OnNcHitTest函数,另一个是在OnLButtonDown时发消息。
实践
一、 OnNcHitTest方案
这个CWnd类的一个方法,我们可以捕捉鼠标点击的坐标,然后将其HTCLIENT结果偷换成HTCAPTION,这样就可以让系统误以为鼠标左键点击的是标题栏,就进入了拖拽模式了。官网参考点这里。
代码十分简单,只需要重载OnNcHitTest就可以。代码填加三处:
1. 头文件
afx_msg LRESULT OnNcHitTest(CPoint pt);
2. 注册消息
BEGIN_MESSAGE_MAP(CAfloatWindowDlg, CDialogEx) ON_WM_SYSCOMMAND() ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_WM_NCHITTEST() END_MESSAGE_MAP()
3. 函数编写
LRESULT CAfloatWindowDlg::OnNcHitTest(CPoint pt) { LRESULT nHitTest = CDialog::OnNcHitTest(pt); if(nHitTest == HTCLIENT) { nHitTest = HTCAPTION; } return nHitTest; }
二、 OnLButtonDown方案
在程序获得左键按下的状态时,发送以下任一系统消息都可以实现悬浮窗的拖拽。
1.SendMessage(WM_SYSCOMMAND, SC_MOVE | HTCAPTION, 0);
2.PostMessage(WM_NCLBUTTONDOWN,HTCAPTION,MAKELPARAM(point.x,point.y));
三、 无边框窗体
Dialog属性中,将Border的属性设为None。
四、 显示png图片
VC对显示png并没有提供很好的支持。本以为像bmp那样,用Picture Control就可以显示出来呢。现在找到一个临时的方案,在OnPaint中将png图片绘制出来。代码如下:
if (IsIconic()) { ... } else { CImage img; CPaintDC dc(this); if(!img.IsNull()) img.Destroy(); HRESULT result = img.Load(_T("prime.png")); if(!img.IsNull()) img.Draw(dc.m_hDC, 0, 0); img.Destroy(); CDialogEx::OnPaint(); }
源码在此。