关键词:Dock Form,磁性窗体,粘黏窗体
版本:Visual C++ 6.0 或以上均可
原理:
1. 判断是否符合吸附条件,拦截子窗体WM_WINDOWPOSCHANGING消息,将lParam转换为PWINDOWPOS后与主窗体的Rect对比,符合条件时候(比如子窗体right与主窗体的left差距小于10px),修改子窗体状态为“已吸附”,并记录下是吸附在主窗体的哪条边(LEFT、RIGHT、TOP、BOTTOM),然后记录下与主窗体的x,y的差距
2. 拖动主窗体时,同时移动所有已经吸附的子窗体,需要相应主窗体的WM_MOVE、WM_SIZE消息,在这些消息触发时候,根据子窗体吸附的边框和与主窗体x、y差距,计算新坐标之后,移动子窗体。
以上是最简单的条件了,其实上文所述的“主窗体”、“子窗体”,并不是dlg.Create(IDD_XX,pParent)中的pParent父级的意思。而是相对于吸附和被吸附的对象
并且10px我是直接写在了函数之中,大家可以随便改
子窗体中需要实现的代码:
在我的代码中,继承了CDialog对象(VS2008 ↑ 可以继承CDialogEx对象)为CMagnetDialog
新建private变量:CWnd* m_pMainDlg;CArray<CWnd*,CWnd*&> m_pMagnetismList;
· 当m_pMainDlg不为NULL时,表示此窗体是m_pMainDlg的子窗体,设置m_pMainDlg的对应函数是SetMainDlg(CWnd* pWnd);。
· m_pMagnetismList.GetSize() >0时,则表示此窗体下面有很多子窗体.
现假设新建了A、B、C三个窗体,A是主窗体,B、C都是A的子窗体
在B、C的InitDialog中写到:
this->SetMainDlg(A);
这样就将A设置成了B、C的子窗体
拦截消息:
以上代码并不是完整代码,只是实现了一些过程
完整代码请在这里下载:
http://download.csdn.net/source/2710558
这是第一个版本,在windows下 开启"拖动时显示窗口内容"下效果比较明显,千千静听只所以不受"拖动是显示窗口内容"的限制,是因为它没有标题栏,然后重写了一些代码,实现鼠标点击窗体任意部分后拖动窗体方式,目前这代码中只是简单的实现了鼠标点击之后发送HIT_TEST消息欺骗的方式,这和点击标题栏无异.以后再研究一下鼠标点击后拖动窗体,主要在于要平滑,我看网上很多例子都是很简单的,那种点住后用力甩都可以把窗体甩出去.
一些细节:
当子窗体和主窗体的某一边在10px的差距之内的时候,移动子窗体时,会有平滑移动的功能(总贴着主窗体的边)
当子窗体已经吸附,Resize子窗体时候,当子窗体已吸附的相邻的两条边会与主窗体的那两边有磁性功能,自己试一下吧
第二个版本中,将会实现如下功能:
1. 鼠标点击窗体任意部分后可拖动窗体(这样就可以无视“拖动时显示窗口内容”了)
2. 当有子窗体B吸附在主窗体上之后,别的子窗体C也可以吸附在这个子窗体B上。直到B失去吸附(移动或者Resize超过10px范围)
3. 磁性功能增强,子窗体移动到任意子窗体的某边时,吸附,Resize也同样带磁性,如图2
完整代码请在这里下载:
http://download.csdn.net/source/2710558