随笔-88  评论-224  文章-22  trackbacks-0
  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, 00, 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==|| -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 春秋十二月 阅读(2074) 评论(0)  编辑 收藏 引用 所属分类: C/C++

只有注册用户登录后才能发表评论。
【推荐】超50万行VC++源码: 大型组态工控、电力仿真CAD与GIS源码库
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理