1/***************************************************************************************
2 邻接矩阵----用来表示所有窗口之间的邻接关系,值1表示两个窗口间相交或相切,值0表示
3 两个窗口间相离,实际存储的是若干窗口组成的非连通无向图结构
4 粘合窗口----由邻接矩阵生成的包含老板窗口的集合,当鼠标按在老板窗口上移动时,整个
5 粘合窗口跟随移动,实际存储的是含有老板窗口的一个连通分量
6 老板窗口----只有当鼠标左键按在此窗口时,才能移动整个粘合窗口,仅允许有一个老板窗口
7
8 2009-12-11 当新建客口时,能正确构建邻接矩阵和粘合窗口列表; 当关闭窗口时,能正确重组邻接矩阵
9 和粘合窗口列表当大小改变时(如最大化,最小化时),能更新邻接矩阵和粘合窗口列表
10 2009-12-30 改进了矩形相切条件的精确判断
11 2009-12-31 支持老板窗口能连续独立移动
12****************************************************************************************/
13
14CWndMagnet::CWndMagnet():
15m_hLead(0)
16{
17}
18
19CWndMagnet::~CWndMagnet()
20{
21}
22
23/**
24 @brief 增加磁性窗口
25 @param hWnd 需要组合分离的窗口
26 * 一般在窗口初始化或创建时调用此方法,加入待组合分离的窗口,注意窗口句柄有效性
27*/
28void CWndMagnet::AddMagnetWnd(HWND hWnd)
29{
30 if (!hWnd || !IsWindow(hWnd)) return;
31 int uIndex = m_map_magWnd.size();
32 pair<map<HWND,int>::iterator,bool> pr = m_map_magWnd.insert(make_pair(hWnd, uIndex));
33 if (!pr.second) return;
34 Add2DMatrix();
35}
36
37/**
38 @brief 移除磁性窗口
39 @param hWnd 需要移除的窗口句柄
40 * 一般在窗口关闭或销毁时调用此方法,移除不组合分离的窗口,注意窗口句柄有效性
41*/
42void CWndMagnet::RemoveMagnetWnd(HWND hWnd)
43{
44 if (!hWnd || !IsWindow(hWnd)) return;
45 m_map_leadWnd.erase(hWnd);
46 Delete2DMatrix(hWnd);
47 DeleteMagWnd(hWnd);
48 UpdateLeadWndSet(hWnd);
49}
50
51/*******************************************************************************************
52 以下为消息映射处理方法,在窗口对应消息处理中调用
53(1) 在OnLButtonDown调用::SendMessage(m_hWnd,WM_SYSCOMMAND,0xF012,0)来实现按客户区移动时
54 经测试发现: 当鼠标左键按在标题栏移动窗口时,而后释放鼠标左键,却收不到WM_NCLBUTTONUP消息,但收到了
55 WM_NCLBUTTONDOWN消息.同理当鼠标左键按在客户区移动窗口时,,而后释放鼠标左键,却收不了WM_LBUTTONUP
56 消息,但收到了WM_LBUTTONDOWN消息.这是移动窗口时发现的规律,本质上是当鼠标左键释放时来更新粘合窗口列表,
57 但鉴于此规律,正好符合调用来更新粘合窗口列表
58(2) 如果应用程序调用了OnLButtonDown或OnNcLButtonDown则在点击窗体时就会粘在一起,否则只有移动时
59 才粘在一起
60********************************************************************************************/
61
62/**
63 @brief 鼠标左键在老板窗口客户区按下事件处理方法
64 @param hWnd 窗口句柄
65 * 这是为了使老板窗口有机会能独立连续移动调用的方法
66*/
67void CWndMagnet::OnLButtonDown(HWND hWnd)
68{
69 if (!hWnd || !IsWindow(hWnd)) return;
70 if (hWnd != m_hLead) return;
71 // Update2DMatrix(hWnd);
72 UpdateLeadWndSet(hWnd);
73}
74
75/**
76 @brief 鼠标左键在老板窗口非客户区按下事件处理方法
77 @param hWnd 窗口句柄
78 * 这是为了使老板窗口有机会能独立连续移动调用的方法
79*/
80void CWndMagnet::OnNcLButtonDown(HWND hWnd)
81{
82 if (!hWnd || !IsWindow(hWnd)) return;
83 if (hWnd != m_hLead) return;
84 UpdateLeadWndSet(hWnd);
85}
86
87/**
88 @brief 鼠标移动事件处理方法
89 @param hWnd 窗口句柄
90 @param lpRect 窗口矩形区域
91*/
92void CWndMagnet::OnMoving(HWND hWnd, LPRECT lpRect)
93{
94 if (!m_map_leadWnd.empty()&&hWnd==m_hLead) // return;
95 {
96 MoveLeadWndSet(hWnd, lpRect);
97 }
98 else
99 {
100 Update2DMatrix(hWnd, lpRect);
101 //移动老板窗口时,使其有机会能独立连续移动
102 if (hWnd!=m_hLead)
103 {
104 UpdateLeadWndSet(hWnd, lpRect);
105 }
106 }
107}
108
109/**
110 @brief 窗口大小改变后事件处理方法
111 @param hWnd 窗口句柄
112 @param uType 大小变化类型
113 * 当大小改变时更新邻接矩阵
114*/
115void CWndMagnet::OnSize(HWND hWnd, UINT uType)
116{
117 if (!hWnd || !IsWindow(hWnd)) return;
118 switch (uType)
119 {
120 case SIZE_RESTORED:
121 case SIZE_MINIMIZED:
122 case SIZE_MAXIMIZED:
123 {
124 Update2DMatrix(hWnd);
125 UpdateLeadWndSet(hWnd);
126 }
127 break;
128
129 case SIZE_MAXSHOW:
130 {
131 }
132 break;
133 }
134}
135
136/**************************************************************************
137 以下为实现方法,在类内部调用以实现公有方法的功能
138**************************************************************************/
139void CWndMagnet::DeleteMagWnd(HWND hWnd)
140{
141 map<HWND,int>::iterator iter = m_map_magWnd.find(hWnd);
142 if (iter==m_map_magWnd.end()) return;
143
144 int index = (*iter).second;
145 m_map_magWnd.erase(iter);
146 for (iter = m_map_magWnd.begin(); iter != m_map_magWnd.end(); ++iter)
147 {
148 int& indexTemp = (*iter).second;
149 if ( indexTemp > index) --indexTemp;
150 }
151}
152//当新建窗口时要调用此函数来增加对应的邻接矩阵值
153void CWndMagnet::Add2DMatrix()
154{
155 int uColCount = m_map_magWnd.size();
156 int uRowCount = m_vec_2DMatrix.size();
157 for (int row = 0; row < uRowCount; ++row)
158 {
159 for (int col = uRowCount; col < uColCount; ++col)
160 {
161 m_vec_2DMatrix[row].push_back(false);
162 }
163 }
164 vector<bool> vec_bool;
165 vec_bool.resize(uColCount);
166 m_vec_2DMatrix.push_back(vec_bool);
167}
168//当窗口销毁时要调用此函数来删除对应的邻接矩阵值
169void CWndMagnet::Delete2DMatrix(HWND hWnd)
170{
171 map<HWND,int>::iterator mapIter = m_map_magWnd.find(hWnd);
172 if (mapIter==m_map_magWnd.end()) return;
173
174 int index = (*mapIter).second, row, col;
175 vector<vector<bool> >::iterator iter;
176 for (vector<vector<bool> >::iterator iter1 = m_vec_2DMatrix.begin(); iter1 != m_vec_2DMatrix.end(); ++iter1)
177 {
178 row = distance(m_vec_2DMatrix.begin(), iter1);
179 if (row == index)
180 {
181 iter = iter1;
182 }
183 for (vector<bool>::iterator iter2 = m_vec_2DMatrix[row].begin(); iter2 != m_vec_2DMatrix[row].end(); ++iter2)
184 {
185 if (distance(m_vec_2DMatrix[row].begin(),iter2)==index)
186 {
187 m_vec_2DMatrix[row].erase(iter2); break;
188 }
189 }
190 }
191 m_vec_2DMatrix.erase(iter);
192}
193//当窗口移动或大小改变时要调用此函数来更新邻接矩阵的值
194//当大小改变时lpRect为0
195void CWndMagnet::Update2DMatrix(HWND hWnd, LPRECT lpRect)
196{
197 map<HWND,int>::iterator iter = m_map_magWnd.find(hWnd);
198 if (iter == m_map_magWnd.end()) return;
199
200 UINT uRow = (*iter).second, uCol;
201 HWND hWndTemp;
202 RECT rcWnd,rcTemp; GetWindowRect(hWnd,&rcWnd);
203 for (iter = m_map_magWnd.begin(); iter != m_map_magWnd.end(); ++iter)
204 {
205 hWndTemp = (*iter).first; uCol = (*iter).second;
206 if (hWnd != hWndTemp)
207 {
208 GetWindowRect(hWndTemp, &rcTemp);
209 if (0 == lpRect)
210 {
211 RECT rcInter;
212 if (IntersectRect(&rcInter,&rcWnd,&rcTemp)
213 ||rcWnd.left==rcTemp.right||rcWnd.right==rcTemp.left
214 ||rcWnd.top==rcTemp.bottom||rcWnd.bottom==rcTemp.top
215 )
216 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
217 else
218 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
219 }
220 else
221 {
222 long lWidth = lpRect->right-lpRect->left, lHeight = lpRect->bottom-lpRect->top;
223 long lOffX = lWidth/2, lOffY = lHeight/2;
224 POINT ptCenter = { lpRect->left + lOffX, lpRect->top + lOffY };
225 RECT rcLeft, rcTop, rcRight, rcBottom, rcCenter;
226
227 SetRect(&rcLeft, rcTemp.left-s_c_iThreshold-lOffX, rcTemp.top-lOffY,
228 rcTemp.left-lOffX, rcTemp.bottom+lOffY);
229 SetRect(&rcTop, rcTemp.left-lOffX, rcTemp.top-s_c_iThreshold-lOffY,
230 rcTemp.right+lOffX, rcTemp.top-lOffY);
231 SetRect(&rcRight, rcTemp.right+lOffX, rcTemp.top-lOffY,
232 rcTemp.right+s_c_iThreshold+lOffX, rcTemp.bottom+lOffY);
233 SetRect(&rcBottom, rcTemp.left-lOffX, rcTemp.bottom+lOffY,
234 rcTemp.right+lOffX, rcTemp.bottom+s_c_iThreshold+lOffY);
235 SetRect(&rcCenter, rcTemp.left-lOffX, rcTemp.top-lOffY,
236 rcTemp.right+lOffX, rcTemp.bottom+lOffY);
237
238 /************************************************************************
239 nOffset指示组合或分离时的矩形偏移值,默认为0
240 PtInRect判断一个点是否在指定矩形内,意味着不包含底边和右边
241 ************************************************************************/
242 int nOffset = 0;
243 if(!m_vec_2DMatrix[uRow][uCol])
244 {
245 if (PtInRect(&rcLeft, ptCenter))
246 {
247 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
248 lpRect->right = rcTemp.left - nOffset;
249 lpRect->left = lpRect->right - lWidth;
250 }
251 else if (PtInRect(&rcTop, ptCenter))
252 {
253 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
254 lpRect->bottom = rcTemp.top - nOffset;
255 lpRect->top = lpRect->bottom - lHeight;
256 }
257 else if (PtInRect(&rcRight, ptCenter))
258 {
259 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
260 lpRect->left = rcTemp.right + nOffset;
261 lpRect->right = lpRect->left + lWidth;
262 }
263 else if (PtInRect(&rcBottom, ptCenter))
264 {
265 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
266 lpRect->top = rcTemp.bottom + nOffset;
267 lpRect->bottom = lpRect->top + lHeight;
268 }
269 else if (PtInRect(&rcCenter, ptCenter))
270 {
271 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = true;
272 }
273
274 }
275 else
276 {
277 if (!PtInRect(&rcLeft, ptCenter)&&!PtInRect(&rcTop, ptCenter)&&!PtInRect(&rcRight, ptCenter)
278 &&!PtInRect(&rcBottom, ptCenter)&&!PtInRect(&rcCenter, ptCenter))
279 {
280 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
281 }
282 else
283 {
284 ++nOffset;
285 OffsetRect(&rcLeft, -nOffset, 0); OffsetRect(&rcRight, nOffset, 0);
286 OffsetRect(&rcTop, 0, -nOffset); OffsetRect(&rcBottom, 0, nOffset);
287 if (PtInRect(&rcLeft, ptCenter))
288 {
289 lpRect->right = rcTemp.left - s_c_iThreshold;
290 lpRect->left = lpRect->right - lWidth;
291 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
292 }
293 else if (PtInRect(&rcTop, ptCenter))
294 {
295 lpRect->bottom = rcTemp.top - s_c_iThreshold;
296 lpRect->top = lpRect->bottom - lHeight;
297 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
298 }
299 else if (PtInRect(&rcRight, ptCenter))
300 {
301 lpRect->left = rcTemp.right + s_c_iThreshold;
302 lpRect->right = lpRect->left + lWidth;
303 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
304 }
305 else if (PtInRect(&rcBottom, ptCenter))
306 {
307 lpRect->top = rcTemp.bottom + s_c_iThreshold;
308 lpRect->bottom = lpRect->top + lHeight;
309 m_vec_2DMatrix[uRow][uCol] = m_vec_2DMatrix[uCol][uRow] = false;
310 }
311 }
312 }
313 }
314 }
315 }
316}
317//当移动或击点窗口时调用此函数更新粘合窗口列表
318//当点击窗口时,lpRect为0
319void CWndMagnet::UpdateLeadWndSet(HWND hWnd, LPCRECT lpRect /**//*=0*/)
320{
321 if (m_vec_2DMatrix.empty()) return;
322
323 map<HWND,int>::iterator iter = m_map_magWnd.find(m_hLead);
324 if (iter == m_map_magWnd.end()) return;
325
326 m_map_leadWnd.clear();
327 int lead_wnd_index = (*iter).second;
328 int rows = m_vec_2DMatrix.size(), cols = m_vec_2DMatrix[0].size();
329 assert(rows == cols);
330
331 vector<int> vecCol;
332 vector<bool> vecVisited(rows);
333 DFS(lead_wnd_index, vecVisited, vecCol);
334
335 RECT rcLead; GetWindowRect(m_hLead, &rcLead);
336 for (vector<int>::iterator vecIter = vecCol.begin()+1; vecIter!=vecCol.end();++vecIter)
337 {
338 int index = *vecIter;
339 for (iter = m_map_magWnd.begin(); iter != m_map_magWnd.end(); ++iter)
340 {
341 if ((*iter).second==index)
342 {
343 HWND hTemp = (*iter).first; RECT rcTemp;
344 GetWindowRect(hTemp, &rcTemp);
345 LPCRECT pRect = 0;
346 if (0==lpRect||hWnd!=m_hLead)
347 pRect = &rcLead;
348 else
349 pRect = lpRect;
350 POINT pt = {rcTemp.left-pRect->left, rcTemp.top-pRect->top};
351 m_map_leadWnd[hTemp] = pt;
352 break;
353 }
354 }
355 }
356}
357//当移动老板窗口时调用此函数来移动整个粘合窗口
358void CWndMagnet::MoveLeadWndSet(HWND hWnd, LPCRECT lpRect)
359{
360 if (hWnd != m_hLead) return;
361
362 HWND hTemp; RECT rcTemp;
363 long lNewLeft, lNewTop;
364 for (map<HWND,POINT>::iterator Iter = m_map_leadWnd.begin(); Iter != m_map_leadWnd.end();++Iter)
365 {
366 lNewLeft = lpRect->left + (*Iter).second.x;
367 lNewTop = lpRect->top + (*Iter).second.y;
368 hTemp = (*Iter).first; GetWindowRect(hTemp,&rcTemp);
369 if (rcTemp.left != lNewLeft || rcTemp.top != lNewTop)
370 {
371 /***********************************************************************************
372 如果不考虑隐藏窗口,已最小化和最大化窗口,则加上以下代码
373 if ((IsWindowVisible(hTemp))&&!IsIconic(hTemp) && !IsZoomed(hTemp))
374 ************************************************************************************/
375 SetWindowPos(hTemp, 0, lNewLeft, lNewTop, 0, 0, SWP_NOSIZE|SWP_NOZORDER);
376 }
377 }
378}
379
380/*****************************************************************************************
381 下面为实现图深度搜索遍历算法的函数
382 DFS:复杂度为O(N*N),N为无向图的顶点个数,可考虑用邻接表存储图来实现,
383 其复杂度为N+E,N为顶点个数,E为边数
384******************************************************************************************/
385//找到顶点v的第一个邻接点
386int CWndMagnet::GetFirstNeighbor(int v)
387{
388 if (-1==v) return -1;
389 int num = m_vec_2DMatrix.size();
390 assert(v < num);
391 for (int col = 0; col < num; ++col)
392 {
393 if (m_vec_2DMatrix[v][col]) return col;
394 }
395 return -1;
396}
397//找到顶点V的邻接点W的下一个邻接点
398int CWndMagnet::GetNextNeighbor(int v, int w)
399{
400 if (-1==v || -1==w) return -1;
401 int num = m_vec_2DMatrix.size();
402 for (int col = w + 1; col < num; ++col)
403 {
404 if (m_vec_2DMatrix[v][col]) return col;
405 }
406 return -1;
407}
408
409void CWndMagnet::DFS(int v, vector<bool>& vecVisited, vector<int>& vecNeighbor)
410{
411 vecVisited[v] = true;
412 vecNeighbor.push_back(v);
413 int w = GetFirstNeighbor(v);
414 for (; w !=-1 ;)
415 {
416 if (!vecVisited[w]) DFS(w, vecVisited, vecNeighbor);
417 w = GetNextNeighbor(v, w);
418 }
419}
posted on 2011-08-27 15:12
春秋十二月 阅读(2612)
评论(0) 编辑 收藏 引用 所属分类:
C/C++