1
/***************************************************************************************
2
鄰接矩陣----用來表示所有窗口之間的鄰接關系,值1表示兩個窗口間相交或相切,值0表示
3
兩個窗口間相離,實際存儲的是若干窗口組成的非連通無向圖結構
4
粘合窗口----由鄰接矩陣生成的包含老板窗口的集合,當鼠標按在老板窗口上移動時,整個
5
粘合窗口跟隨移動,實際存儲的是含有老板窗口的一個連通分量
6
老板窗口----只有當鼠標左鍵按在此窗口時,才能移動整個粘合窗口,僅允許有一個老板窗口
7
8
2009-12-11 當新建客口時,能正確構建鄰接矩陣和粘合窗口列表; 當關閉窗口時,能正確重組鄰接矩陣
9
和粘合窗口列表當大小改變時(如最大化,最小化時),能更新鄰接矩陣和粘合窗口列表
10
2009-12-30 改進了矩形相切條件的精確判斷
11
2009-12-31 支持老板窗口能連續獨立移動
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
* 一般在窗口初始化或創建時調用此方法,加入待組合分離的窗口,注意窗口句柄有效性
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
* 一般在窗口關閉或銷毀時調用此方法,移除不組合分離的窗口,注意窗口句柄有效性
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
以下為消息映射處理方法,在窗口對應消息處理中調用
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
*/
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 鼠標左鍵在老板窗口非客戶區按下事件處理方法
77
@param hWnd 窗口句柄
78
* 這是為了使老板窗口有機會能獨立連續移動調用的方法
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 鼠標移動事件處理方法
89
@param hWnd 窗口句柄
90
@param lpRect 窗口矩形區域
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
//移動老板窗口時,使其有機會能獨立連續移動
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
*/
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
以下為實現方法,在類內部調用以實現公有方法的功能
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
//當新建窗口時要調用此函數來增加對應的鄰接矩陣值
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
//當窗口銷毀時要調用此函數來刪除對應的鄰接矩陣值
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
//當窗口移動或大小改變時要調用此函數來更新鄰接矩陣的值
194
//當大小改變時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指示組合或分離時的矩形偏移值,默認為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
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
//當移動老板窗口時調用此函數來移動整個粘合窗口
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
下面為實現圖深度搜索遍歷算法的函數
382
DFS:復雜度為O(N*N),N為無向圖的頂點個數,可考慮用鄰接表存儲圖來實現,
383
其復雜度為N+E,N為頂點個數,E為邊數
384
******************************************************************************************/
385
//找到頂點v的第一個鄰接點
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
//找到頂點V的鄰接點W的下一個鄰接點
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
春秋十二月 閱讀(2633)
評論(0) 編輯 收藏 引用 所屬分類:
C/C++