现在的位置: 首页 > 自动控制 > 工业·编程 > 正文

界面布局动态调整

2013-12-03 00:09 工业·编程 ⁄ 共 2695字 ⁄ 字号 暂无评论

    早在2007年我就写过一篇博客叫可适配控件对话框,那个时候一方面是工作需要研究了这个问题,另一方面是发现论坛里有很多人问相关的问题,于是就把自己的研究成果做了一个小例子发了上来,还写了那篇博客。

      说来惭愧,首先那时那个例子其实是我照着网上一个例子改的,而且基本框架也差不多,我简单加了些自己的东西改了改名就发出来了,唉......如今原作者以无法考正了,在此对其表示感谢吧。然后那个例子其实不是很好用,当时并没有发现什么问题,但是随着工作中使用的增多我发现了不少缺陷,也在工作中不断的改进,终于做出了一个自己用的很舒服的版本。如今三年过去了,再看CSDN界面版仍然有很多网友问及此类问题,VisualEleven力推codeproject上的easysize。easysize当初我也简单看过,不过那时我并没看懂,估计我现在也看不懂,呵呵。不过我觉得我用的这个方法也蛮好的,所以决定再写一篇博客把现在的方法介绍一下,同时整理了一个例子供大家研究。

      处理过这个问题的朋友们就应该知道,所谓的控件动态调整就是在主窗口的OnSize消息里处理一下,根据窗口的大小重新布置控件的位置。而解决这个问题的关键在于如何管理界面中的控件信息,从而可以比较方便的实现对控件的重新布局。我的处理方式是这样的,我定义了一个结构tagCONTROL,其内容如下

  1. /**
  2. *  控件随窗口变化的控制单元
  3. **/
  4. typedef struct tagCONTROL 
  5.     CWnd*   m_pWnd;             //指向控件的指针
  6.     CRect   m_rectWnd;          //控件所占区域
  7. int     m_nMoveXPercent,    //控件沿x轴移动的百分比
  8.             m_nMoveYPercent,    //控件沿y轴移动的百分比
  9.             m_nZoomXPercent,    //控件沿x轴缩放的百分比
  10.             m_nZoomYPercent;    //控件沿y轴缩放的百分比
  11. }ControlInfo, *lpControlInfo; 

从这个定义中我们可以看出tagCONTROL里保存了丰富的对于控件布局的控制信息,这里m_pWnd是指向被控控件的指针,他可以是一个控件也可以是一个窗口,这样就把界面布局的控制元素全都囊括进来了。而移动、缩放的百分比控制使界面布局的控制更加灵活,更加方便。每一个需要调整布局的界面元素都会通过这个结构来保存其信息,而在界面主窗口中维护一个这种结构的列表即可在OnSize函数中方便的实现控件布局的自动调整。

      所谓界面动态调整布局实际上应该有一个参照,也就是说我们应该记录初始显示时界面的大小和此时界面中控件的位置。以后的调整都是基于这些信息的,也就是说tagCONTROL中保存的信息都是通过初始的基本数据起作用的。按着这个思路,在OnSize函数中我是这样实现的

  1. void CAutoFitDlg::OnSize(UINT nType, int cx, int cy) 
  2. //计算窗口宽度和高度的改变量
  3. int nIncrementX = cx - m_nWinWidth; 
  4. int nIncrementY = cy - m_nWinHeight; 
  5. INT_PTR nCount  = m_listCtrlTag.GetSize(); 
  6. for (int i=0; i<nCount; i++) 
  7.     { 
  8. //获取变化控制系数
  9. int nMoveXPercent   = m_listCtrlTag[i]->m_nMoveXPercent; 
  10. int nMoveYPercent   = m_listCtrlTag[i]->m_nMoveYPercent; 
  11. int nZoomXPercent   = m_listCtrlTag[i]->m_nZoomXPercent; 
  12. int nZoomYPercent   = m_listCtrlTag[i]->m_nZoomYPercent; 
  13.         CWnd*   pWndCtrl; 
  14. //获取控件指针
  15.         pWndCtrl = m_listCtrlTag[i]->m_pWnd; 
  16. if(IsWindow(pWndCtrl->GetSafeHwnd())) 
  17.         { 
  18. int nLeft   = m_listCtrlTag[i]->m_rectWnd.left; 
  19. int nTop    = m_listCtrlTag[i]->m_rectWnd.top; 
  20. int nWidth  = m_listCtrlTag[i]->m_rectWnd.Width(); 
  21. int nHeight = m_listCtrlTag[i]->m_rectWnd.Height(); 
  22. //设置新的位置参数
  23.             nLeft   += (nIncrementX*nMoveXPercent/100); 
  24.             nTop    += (nIncrementY*nMoveYPercent/100); 
  25.             nWidth  += (nIncrementX*nZoomXPercent/100); 
  26.             nHeight += (nIncrementY*nZoomYPercent/100); 
  27. //  把控件移动到新位置
  28.             pWndCtrl->MoveWindow(nLeft, nTop, nWidth, nHeight); 
  29.         } 
  30.     } 
  31.     CDialog::OnSize(nType, cx, cy); 

      同时,一个设计良好的界面的一般会有一个最小大小,在这个范围内安排界面布局。通常情况下我们不希望界面小于这个最小大小,这个需求可以通过重载WM_GETMINMAXINFO消息来实现

  1. void CAutoFitDlg::OnGetMinMaxInfo(MINMAXINFO* lpMMI) 
  2. //设置窗口的最小大小
  3.     lpMMI->ptMinTrackSize = m_ptMinTrackSize; 
  4.     CDialog::OnGetMinMaxInfo(lpMMI); 

      这样一来,只要我们设计好控制信息,我们设计的界面即使被用户缩放和拖拽也可以体现出良好的布局。这个方案是我这些年来一直在项目中采用的,我不敢说它是完美的,但是却是能够满足一般的需求。如果大家在对这个方案的研究和使用中发现什么问题或是可以改进的地方还希望可以告诉我,我会加以改进再和朋友们分享。

给我留言

留言无头像?