1
/***************************************************************************************
2
鄰接矩陣----用來(lái)表示所有窗口之間的鄰接關(guān)系,值1表示兩個(gè)窗口間相交或相切,值0表示
3
兩個(gè)窗口間相離,實(shí)際存儲(chǔ)的是若干窗口組成的非連通無(wú)向圖結(jié)構(gòu)
4
粘合窗口----由鄰接矩陣生成的包含老板窗口的集合,當(dāng)鼠標(biāo)按在老板窗口上移動(dòng)時(shí),整個(gè)
5
粘合窗口跟隨移動(dòng),實(shí)際存儲(chǔ)的是含有老板窗口的一個(gè)連通分量
6
老板窗口----只有當(dāng)鼠標(biāo)左鍵按在此窗口時(shí),才能移動(dòng)整個(gè)粘合窗口,僅允許有一個(gè)老板窗口
7
8
2009-12-11 當(dāng)新建客口時(shí),能正確構(gòu)建鄰接矩陣和粘合窗口列表; 當(dāng)關(guān)閉窗口時(shí),能正確重組鄰接矩陣
9
和粘合窗口列表當(dāng)大小改變時(shí)(如最大化,最小化時(shí)),能更新鄰接矩陣和粘合窗口列表
10
2009-12-30 改進(jìn)了矩形相切條件的精確判斷
11
2009-12-31 支持老板窗口能連續(xù)獨(dú)立移動(dòng)
12
****************************************************************************************/
13
14
CWndMagnet::CWndMagnet():
15
m_hLead(0)
16

{
17
}
18
19
CWndMagnet::~CWndMagnet()
20

{
21
}
22
23
/**
24
@brief 增加磁性窗口
25
@param hWnd 需要組合分離的窗口
26
* 一般在窗口初始化或創(chuàng)建時(shí)調(diào)用此方法,加入待組合分離的窗口,注意窗口句柄有效性
27
*/
28
void 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
* 一般在窗口關(guān)閉或銷(xiāo)毀時(shí)調(diào)用此方法,移除不組合分離的窗口,注意窗口句柄有效性
41
*/
42
void 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
以下為消息映射處理方法,在窗口對(duì)應(yīng)消息處理中調(diào)用
53
(1) 在OnLButtonDown調(diào)用::SendMessage(m_hWnd,WM_SYSCOMMAND,0xF012,0)來(lái)實(shí)現(xiàn)按客戶(hù)區(qū)移動(dòng)時(shí)
54
經(jīng)測(cè)試發(fā)現(xiàn): 當(dāng)鼠標(biāo)左鍵按在標(biāo)題欄移動(dòng)窗口時(shí),而后釋放鼠標(biāo)左鍵,卻收不到WM_NCLBUTTONUP消息,但收到了
55
WM_NCLBUTTONDOWN消息.同理當(dāng)鼠標(biāo)左鍵按在客戶(hù)區(qū)移動(dòng)窗口時(shí),,而后釋放鼠標(biāo)左鍵,卻收不了WM_LBUTTONUP
56
消息,但收到了WM_LBUTTONDOWN消息.這是移動(dòng)窗口時(shí)發(fā)現(xiàn)的規(guī)律,本質(zhì)上是當(dāng)鼠標(biāo)左鍵釋放時(shí)來(lái)更新粘合窗口列表,
57
但鑒于此規(guī)律,正好符合調(diào)用來(lái)更新粘合窗口列表
58
(2) 如果應(yīng)用程序調(diào)用了OnLButtonDown或OnNcLButtonDown則在點(diǎn)擊窗體時(shí)就會(huì)粘在一起,否則只有移動(dòng)時(shí)
59
才粘在一起
60
********************************************************************************************/
61
62
/**
63
@brief 鼠標(biāo)左鍵在老板窗口客戶(hù)區(qū)按下事件處理方法
64
@param hWnd 窗口句柄
65
* 這是為了使老板窗口有機(jī)會(huì)能獨(dú)立連續(xù)移動(dòng)調(diào)用的方法
66
*/
67
void 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 鼠標(biāo)左鍵在老板窗口非客戶(hù)區(qū)按下事件處理方法
77
@param hWnd 窗口句柄
78
* 這是為了使老板窗口有機(jī)會(huì)能獨(dú)立連續(xù)移動(dòng)調(diào)用的方法
79
*/
80
void 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 鼠標(biāo)移動(dòng)事件處理方法
89
@param hWnd 窗口句柄
90
@param lpRect 窗口矩形區(qū)域
91
*/
92
void 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
//移動(dòng)老板窗口時(shí),使其有機(jī)會(huì)能獨(dú)立連續(xù)移動(dòng)
102
if (hWnd!=m_hLead)
103
{
104
UpdateLeadWndSet(hWnd, lpRect);
105
}
106
}
107
}
108
109
/**
110
@brief 窗口大小改變后事件處理方法
111
@param hWnd 窗口句柄
112
@param uType 大小變化類(lèi)型
113
* 當(dāng)大小改變時(shí)更新鄰接矩陣
114
*/
115
void 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
以下為實(shí)現(xiàn)方法,在類(lèi)內(nèi)部調(diào)用以實(shí)現(xiàn)公有方法的功能
138
**************************************************************************/
139
void 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
//當(dāng)新建窗口時(shí)要調(diào)用此函數(shù)來(lái)增加對(duì)應(yīng)的鄰接矩陣值
153
void 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
//當(dāng)窗口銷(xiāo)毀時(shí)要調(diào)用此函數(shù)來(lái)刪除對(duì)應(yīng)的鄰接矩陣值
169
void 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
//當(dāng)窗口移動(dòng)或大小改變時(shí)要調(diào)用此函數(shù)來(lái)更新鄰接矩陣的值
194
//當(dāng)大小改變時(shí)lpRect為0
195
void 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指示組合或分離時(shí)的矩形偏移值,默認(rèn)為0
240
PtInRect判斷一個(gè)點(diǎn)是否在指定矩形內(nèi),意味著不包含底邊和右邊
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
//當(dāng)移動(dòng)或擊點(diǎn)窗口時(shí)調(diào)用此函數(shù)更新粘合窗口列表
318
//當(dāng)點(diǎn)擊窗口時(shí),lpRect為0
319
void 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
//當(dāng)移動(dòng)老板窗口時(shí)調(diào)用此函數(shù)來(lái)移動(dòng)整個(gè)粘合窗口
358
void 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
下面為實(shí)現(xiàn)圖深度搜索遍歷算法的函數(shù)
382
DFS:復(fù)雜度為O(N*N),N為無(wú)向圖的頂點(diǎn)個(gè)數(shù),可考慮用鄰接表存儲(chǔ)圖來(lái)實(shí)現(xiàn),
383
其復(fù)雜度為N+E,N為頂點(diǎn)個(gè)數(shù),E為邊數(shù)
384
******************************************************************************************/
385
//找到頂點(diǎn)v的第一個(gè)鄰接點(diǎn)
386
int 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
//找到頂點(diǎn)V的鄰接點(diǎn)W的下一個(gè)鄰接點(diǎn)
398
int 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
409
void 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
春秋十二月 閱讀(2639)
評(píng)論(0) 編輯 收藏 引用 所屬分類(lèi):
C/C++